@gpc-cli/core 0.9.39 → 0.9.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +50 -1
- package/dist/index.js +166 -23
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/output.ts","../src/plugins.ts","../src/commands/apps.ts","../src/commands/releases.ts","../src/utils/file-validation.ts","../src/utils/bcp47.ts","../src/utils/image-validation.ts","../src/utils/fastlane.ts","../src/utils/listing-text.ts","../src/commands/listings.ts","../src/commands/migrate.ts","../src/utils/validation.ts","../src/utils/release-notes.ts","../src/commands/validate.ts","../src/commands/publish.ts","../src/commands/reviews.ts","../src/utils/sentiment.ts","../src/commands/subscriptions.ts","../src/commands/vitals.ts","../src/commands/iap.ts","../src/commands/purchases.ts","../src/commands/pricing.ts","../src/commands/reports.ts","../src/commands/users.ts","../src/commands/grants.ts","../src/commands/testers.ts","../src/utils/git-notes.ts","../src/commands/app-recovery.ts","../src/commands/data-safety.ts","../src/commands/external-transactions.ts","../src/commands/device-tiers.ts","../src/commands/one-time-products.ts","../src/utils/spinner.ts","../src/utils/train-state.ts","../src/commands/train.ts","../src/commands/games.ts","../src/commands/enterprise.ts","../src/audit.ts","../src/commands/quota.ts","../src/utils/safe-path.ts","../src/commands/init.ts","../src/preflight/types.ts","../src/preflight/config.ts","../src/preflight/aab-reader.ts","../src/preflight/manifest-parser.ts","../src/preflight/scanners/manifest-scanner.ts","../src/preflight/scanners/permissions-scanner.ts","../src/preflight/scanners/native-libs-scanner.ts","../src/preflight/scanners/metadata-scanner.ts","../src/preflight/scanners/secrets-scanner.ts","../src/preflight/scan-files.ts","../src/preflight/scanners/billing-scanner.ts","../src/preflight/scanners/privacy-scanner.ts","../src/preflight/scanners/policy-scanner.ts","../src/preflight/scanners/size-scanner.ts","../src/preflight/orchestrator.ts","../src/utils/sort.ts","../src/commands/plugin-scaffold.ts","../src/utils/webhooks.ts","../src/commands/internal-sharing.ts","../src/commands/generated-apks.ts","../src/commands/purchase-options.ts","../src/commands/bundle-analysis.ts","../src/commands/status.ts","../src/commands/changelog.ts"],"sourcesContent":["export class GpcError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly exitCode: number,\n public readonly suggestion?: string,\n ) {\n super(message);\n this.name = \"GpcError\";\n }\n\n toJSON() {\n return {\n success: false,\n error: {\n code: this.code,\n message: this.message,\n suggestion: this.suggestion,\n },\n };\n }\n}\n\nexport class ConfigError extends GpcError {\n constructor(message: string, code: string, suggestion?: string) {\n super(message, code, 1, suggestion);\n this.name = \"ConfigError\";\n }\n}\n\nexport class ApiError extends GpcError {\n constructor(\n message: string,\n code: string,\n public readonly statusCode?: number,\n suggestion?: string,\n ) {\n super(message, code, 4, suggestion);\n this.name = \"ApiError\";\n }\n}\n\nexport class NetworkError extends GpcError {\n constructor(message: string, suggestion?: string) {\n super(message, \"NETWORK_ERROR\", 5, suggestion);\n this.name = \"NetworkError\";\n }\n}\n","import type { OutputFormat } from \"@gpc-cli/config\";\nimport process from \"node:process\";\n\n// Minimal color helpers (no external dep, respects NO_COLOR / FORCE_COLOR)\nfunction isColorEnabled(): boolean {\n if (process.env[\"NO_COLOR\"] !== undefined && process.env[\"NO_COLOR\"] !== \"\") return false;\n const fc = process.env[\"FORCE_COLOR\"];\n if (fc === \"1\" || fc === \"2\" || fc === \"3\") return true;\n return process.stdout.isTTY ?? false;\n}\nfunction ansi(code: number, s: string): string {\n return isColorEnabled() ? `\\x1b[${code}m${s}\\x1b[0m` : s;\n}\nfunction bold(s: string): string {\n return ansi(1, s);\n}\nfunction dim(s: string): string {\n return ansi(2, s);\n}\n\nexport function detectOutputFormat(): OutputFormat {\n return process.stdout.isTTY ? \"table\" : \"json\";\n}\n\nexport function formatOutput(data: unknown, format: OutputFormat, redact = true): string {\n const safe = redact ? redactSensitive(data) : data;\n switch (format) {\n case \"json\":\n return formatJson(safe);\n case \"yaml\":\n return formatYaml(safe);\n case \"markdown\":\n return formatMarkdown(safe);\n case \"table\":\n return formatTable(safe);\n case \"junit\":\n return formatJunit(safe);\n default:\n return formatJson(safe);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Sensitive field redaction\n// ---------------------------------------------------------------------------\n\nexport const SENSITIVE_KEYS = new Set([\n \"private_key\",\n \"privateKey\",\n \"private_key_id\",\n \"privateKeyId\",\n \"accessToken\",\n \"access_token\",\n \"refreshToken\",\n \"refresh_token\",\n \"client_secret\",\n \"clientSecret\",\n \"token\",\n \"password\",\n \"secret\",\n \"credentials\",\n \"keyFile\",\n \"key_file\",\n \"serviceAccount\",\n \"service-account\",\n \"apiKey\",\n \"api_key\",\n \"auth_token\",\n \"bearer\",\n \"jwt\",\n \"signing_key\",\n \"keystore_password\",\n \"store_password\",\n \"key_password\",\n]);\n\nconst REDACTED = \"[REDACTED]\";\n\n/** Recursively redact sensitive fields from data before output. */\nexport function redactSensitive(data: unknown): unknown {\n if (data === null || data === undefined) return data;\n\n if (typeof data === \"string\") return data;\n if (typeof data === \"number\" || typeof data === \"boolean\") return data;\n\n if (Array.isArray(data)) {\n return data.map((item) => redactSensitive(item));\n }\n\n if (typeof data === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data as Record<string, unknown>)) {\n if (SENSITIVE_KEYS.has(key)) {\n result[key] = REDACTED;\n } else {\n result[key] = redactSensitive(value);\n }\n }\n return result;\n }\n\n return data;\n}\n\nfunction formatJson(data: unknown): string {\n return JSON.stringify(data, null, 2);\n}\n\nfunction formatYaml(data: unknown, indent = 0): string {\n if (data === null || data === undefined) {\n return \"null\";\n }\n\n if (typeof data === \"string\") {\n return data.includes(\"\\n\")\n ? `|\\n${data\n .split(\"\\n\")\n .map((l) => `${\" \".repeat(indent + 1)}${l}`)\n .join(\"\\n\")}`\n : data;\n }\n\n if (typeof data === \"number\" || typeof data === \"boolean\") {\n return String(data);\n }\n\n if (Array.isArray(data)) {\n if (data.length === 0) return \"[]\";\n return data\n .map((item) => {\n const value = formatYaml(item, indent + 1);\n const prefix = `${\" \".repeat(indent)}- `;\n if (typeof item === \"object\" && item !== null && !Array.isArray(item)) {\n const lines = value.split(\"\\n\");\n return `${prefix}${lines[0]}\\n${lines\n .slice(1)\n .map((l) => `${\" \".repeat(indent)} ${l}`)\n .join(\"\\n\")}`;\n }\n return `${prefix}${value}`;\n })\n .join(\"\\n\");\n }\n\n if (typeof data === \"object\") {\n const entries = Object.entries(data as Record<string, unknown>);\n if (entries.length === 0) return \"{}\";\n return entries\n .map(([key, value]) => {\n if (typeof value === \"object\" && value !== null) {\n return `${\" \".repeat(indent)}${key}:\\n${formatYaml(value, indent + 1)}`;\n }\n return `${\" \".repeat(indent)}${key}: ${formatYaml(value, indent)}`;\n })\n .join(\"\\n\");\n }\n\n return String(data);\n}\n\nconst DEFAULT_CELL_WIDTH = 60;\n\nfunction computeMaxCellWidth(colCount: number): number {\n const cols = process.stdout.columns;\n if (cols && colCount > 0) {\n return Math.max(20, Math.floor(cols / colCount) - 2);\n }\n return DEFAULT_CELL_WIDTH;\n}\n\nfunction truncateCell(value: string, maxWidth = DEFAULT_CELL_WIDTH): string {\n if (value.length <= maxWidth) return value;\n return value.slice(0, maxWidth - 3) + \"...\";\n}\n\nfunction isNumericCell(value: string): boolean {\n return /^-?\\d[\\d,]*(\\.\\d+)?%?$/.test(value.trim());\n}\n\nfunction cellValue(val: unknown): string {\n if (val === null || val === undefined) return \"\";\n if (typeof val === \"object\") {\n if (Array.isArray(val)) return val.length === 0 ? \"\" : JSON.stringify(val);\n return JSON.stringify(val);\n }\n return String(val);\n}\n\nfunction formatTable(data: unknown): string {\n const rows = toRows(data);\n if (rows.length === 0) return \"\";\n\n const firstRow = rows[0];\n if (!firstRow) return \"\";\n const keys = Object.keys(firstRow);\n if (keys.length === 0) return \"\";\n\n const colCount = keys.length;\n const maxCellWidth = computeMaxCellWidth(colCount);\n\n const widths = keys.map((key) =>\n Math.max(\n key.length,\n ...rows.map((row) => truncateCell(cellValue(row[key]), maxCellWidth).length),\n ),\n );\n\n // Detect numeric columns (right-align numbers)\n const isNumeric = keys.map((key) =>\n rows.every((row) => {\n const v = cellValue(row[key]);\n return v === \"\" || isNumericCell(v);\n }),\n );\n\n const header = keys.map((key, i) => bold(key.padEnd(widths[i] ?? 0))).join(\" \");\n const separator = widths.map((w) => dim(\"─\".repeat(w))).join(\" \");\n const body = rows\n .map((row) =>\n keys\n .map((key, i) => {\n const cell = truncateCell(cellValue(row[key]), maxCellWidth);\n const w = widths[i] ?? 0;\n return isNumeric[i] ? cell.padStart(w) : cell.padEnd(w);\n })\n .join(\" \"),\n )\n .join(\"\\n\");\n\n return `${header}\\n${separator}\\n${body}`;\n}\n\nfunction formatMarkdown(data: unknown): string {\n const rows = toRows(data);\n if (rows.length === 0) return \"\";\n\n const firstRow = rows[0];\n if (!firstRow) return \"\";\n const keys = Object.keys(firstRow);\n if (keys.length === 0) return \"\";\n\n const widths = keys.map((key) =>\n Math.max(key.length, ...rows.map((row) => truncateCell(cellValue(row[key])).length)),\n );\n\n const header = `| ${keys.map((key, i) => key.padEnd(widths[i] ?? 0)).join(\" | \")} |`;\n const separator = `| ${widths.map((w) => \"-\".repeat(w)).join(\" | \")} |`;\n const body = rows\n .map(\n (row) =>\n `| ${keys.map((key, i) => truncateCell(cellValue(row[key])).padEnd(widths[i] ?? 0)).join(\" | \")} |`,\n )\n .join(\"\\n\");\n\n return `${header}\\n${separator}\\n${body}`;\n}\n\nfunction toRows(data: unknown): Record<string, unknown>[] {\n if (Array.isArray(data)) {\n return data.filter(\n (item): item is Record<string, unknown> => typeof item === \"object\" && item !== null,\n );\n }\n if (typeof data === \"object\" && data !== null) {\n return [data as Record<string, unknown>];\n }\n return [];\n}\n\n// ---------------------------------------------------------------------------\n// JUnit XML output\n// ---------------------------------------------------------------------------\n\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\nfunction toTestCases(data: unknown, commandName: string): { cases: string[]; failures: number } {\n const cases: string[] = [];\n let failures = 0;\n\n if (Array.isArray(data)) {\n for (let i = 0; i < data.length; i++) {\n const tc = buildTestCase(data[i], commandName, i);\n cases.push(tc.xml);\n if (tc.failed) failures++;\n }\n } else if (typeof data === \"object\" && data !== null) {\n const tc = buildTestCase(data, commandName);\n cases.push(tc.xml);\n if (tc.failed) failures++;\n } else if (typeof data === \"string\") {\n cases.push(\n ` <testcase name=\"${escapeXml(data)}\" classname=\"gpc.${escapeXml(commandName)}\" />`,\n );\n }\n\n return { cases, failures };\n}\n\nfunction buildTestCase(\n item: unknown,\n commandName: string,\n index = 0,\n): { xml: string; failed: boolean } {\n if (typeof item !== \"object\" || item === null) {\n const text = String(item);\n return {\n xml: ` <testcase name=\"${escapeXml(text)}\" classname=\"gpc.${escapeXml(commandName)}\" />`,\n failed: false,\n };\n }\n\n const record = item as Record<string, unknown>;\n\n // Pick the first meaningful identifier, skipping sentinel dash/empty values\n // that commands use as display placeholders (e.g. `name: s[\"name\"] || \"-\"`).\n const CANDIDATE_KEYS = [\n \"name\",\n \"title\",\n \"sku\",\n \"id\",\n \"reviewId\",\n \"productId\",\n \"packageName\",\n \"track\",\n \"trackId\",\n \"versionCode\",\n \"region\",\n \"languageCode\",\n ] as const;\n let resolvedName = `item-${index + 1}`;\n for (const key of CANDIDATE_KEYS) {\n const val = record[key];\n if (val != null && val !== \"\" && val !== \"-\") {\n resolvedName = String(val);\n break;\n }\n }\n const name = escapeXml(resolvedName);\n const classname = `gpc.${escapeXml(commandName)}`;\n\n // Detect threshold breach (vitals)\n const breached = record[\"breached\"];\n if (breached === true) {\n const message = escapeXml(String(record[\"message\"] ?? \"threshold breached\"));\n const details = escapeXml(\n String(record[\"details\"] ?? record[\"metric\"] ?? JSON.stringify(item)),\n );\n return {\n xml: ` <testcase name=\"${name}\" classname=\"${classname}\">\\n <failure message=\"${message}\">${details}</failure>\\n </testcase>`,\n failed: true,\n };\n }\n\n return {\n xml: ` <testcase name=\"${name}\" classname=\"${classname}\" />`,\n failed: false,\n };\n}\n\n/**\n * Auto-pipe `output` to `$PAGER` when:\n * - stdout is a TTY\n * - row count exceeds terminal height\n * - a pager is available in the environment\n *\n * Falls back to `console.log(output)` when pagination is not applicable.\n */\nexport async function maybePaginate(output: string): Promise<void> {\n const isTTY = process.stdout.isTTY;\n const termHeight = process.stdout.rows ?? 24;\n const lineCount = output.split(\"\\n\").length;\n\n if (!isTTY || lineCount <= termHeight) {\n console.log(output);\n return;\n }\n\n const pager = process.env[\"GPC_PAGER\"] ?? process.env[\"PAGER\"] ?? \"less\";\n\n try {\n const { spawn } = await import(\"node:child_process\");\n const child = spawn(pager, [], {\n stdio: [\"pipe\", \"inherit\", \"inherit\"],\n env: { ...process.env, LESS: process.env[\"LESS\"] ?? \"-FRX\" },\n });\n child.stdin.write(output);\n child.stdin.end();\n await new Promise<void>((resolve) => child.on(\"close\", resolve));\n } catch {\n // Pager not available — fall back to plain output\n console.log(output);\n }\n}\n\nexport function formatJunit(data: unknown, commandName = \"command\"): string {\n const { cases, failures } = toTestCases(data, commandName);\n const tests = cases.length;\n\n const lines = [\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>',\n `<testsuites name=\"gpc\" tests=\"${tests}\" failures=\"${failures}\" time=\"0\">`,\n ` <testsuite name=\"${escapeXml(commandName)}\" tests=\"${tests}\" failures=\"${failures}\">`,\n ...cases,\n \" </testsuite>\",\n \"</testsuites>\",\n ];\n\n return lines.join(\"\\n\");\n}\n","import type {\n GpcPlugin,\n PluginHooks,\n BeforeCommandHandler,\n AfterCommandHandler,\n ErrorHandler,\n BeforeRequestHandler,\n AfterResponseHandler,\n CommandEvent,\n CommandResult,\n PluginError,\n PluginCommand,\n PluginManifest,\n PluginPermission,\n RequestEvent,\n ResponseEvent,\n} from \"@gpc-cli/plugin-sdk\";\nimport { GpcError } from \"./errors.js\";\n\n// ---------------------------------------------------------------------------\n// Plugin Manager — orchestrates discovery, loading, and lifecycle\n// ---------------------------------------------------------------------------\n\nconst FIRST_PARTY_PLUGINS = new Set([\n \"@gpc-cli/plugin-ci\",\n \"@gpc-cli/plugin-sdk\",\n]);\n\nexport class PluginManager {\n private plugins: LoadedPlugin[] = [];\n private beforeHandlers: BeforeCommandHandler[] = [];\n private afterHandlers: AfterCommandHandler[] = [];\n private errorHandlers: ErrorHandler[] = [];\n private beforeRequestHandlers: BeforeRequestHandler[] = [];\n private afterResponseHandlers: AfterResponseHandler[] = [];\n private registeredCommands: PluginCommand[] = [];\n\n /** Load and register a plugin */\n async load(plugin: GpcPlugin, manifest?: PluginManifest): Promise<void> {\n const isTrusted = manifest?.trusted ?? FIRST_PARTY_PLUGINS.has(plugin.name);\n\n if (!isTrusted && manifest?.permissions) {\n validatePermissions(manifest.permissions);\n }\n\n const hooks = createHooks(\n this.beforeHandlers,\n this.afterHandlers,\n this.errorHandlers,\n this.beforeRequestHandlers,\n this.afterResponseHandlers,\n this.registeredCommands,\n );\n\n await plugin.register(hooks);\n\n this.plugins.push({\n name: plugin.name,\n version: plugin.version,\n trusted: isTrusted,\n });\n }\n\n /** Run all beforeCommand handlers */\n async runBeforeCommand(event: CommandEvent): Promise<void> {\n for (const handler of this.beforeHandlers) {\n await handler(event);\n }\n }\n\n /** Run all afterCommand handlers */\n async runAfterCommand(event: CommandEvent, result: CommandResult): Promise<void> {\n for (const handler of this.afterHandlers) {\n await handler(event, result);\n }\n }\n\n /** Run all onError handlers */\n async runOnError(event: CommandEvent, error: PluginError): Promise<void> {\n for (const handler of this.errorHandlers) {\n try {\n await handler(event, error);\n } catch {\n // Don't let error handlers crash the process\n }\n }\n }\n\n /** Run all beforeRequest handlers */\n async runBeforeRequest(event: RequestEvent): Promise<void> {\n for (const handler of this.beforeRequestHandlers) {\n try {\n await handler(event);\n } catch {\n // Don't let request hooks block API calls\n }\n }\n }\n\n /** Run all afterResponse handlers */\n async runAfterResponse(event: RequestEvent, response: ResponseEvent): Promise<void> {\n for (const handler of this.afterResponseHandlers) {\n try {\n await handler(event, response);\n } catch {\n // Don't let response hooks crash the process\n }\n }\n }\n\n /** Get commands registered by plugins */\n getRegisteredCommands(): PluginCommand[] {\n return [...this.registeredCommands];\n }\n\n /** Get list of loaded plugins */\n getLoadedPlugins(): LoadedPlugin[] {\n return [...this.plugins];\n }\n\n /** Whether any request/response hooks are registered */\n hasRequestHooks(): boolean {\n return this.beforeRequestHandlers.length > 0 || this.afterResponseHandlers.length > 0;\n }\n\n /** Reset (for testing) */\n reset(): void {\n this.plugins = [];\n this.beforeHandlers = [];\n this.afterHandlers = [];\n this.errorHandlers = [];\n this.beforeRequestHandlers = [];\n this.afterResponseHandlers = [];\n this.registeredCommands = [];\n }\n}\n\nexport interface LoadedPlugin {\n name: string;\n version: string;\n trusted: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Hook factory\n// ---------------------------------------------------------------------------\n\nfunction createHooks(\n beforeHandlers: BeforeCommandHandler[],\n afterHandlers: AfterCommandHandler[],\n errorHandlers: ErrorHandler[],\n beforeRequestHandlers: BeforeRequestHandler[],\n afterResponseHandlers: AfterResponseHandler[],\n registeredCommands: PluginCommand[],\n): PluginHooks {\n return {\n beforeCommand(handler) {\n beforeHandlers.push(handler);\n },\n afterCommand(handler) {\n afterHandlers.push(handler);\n },\n onError(handler) {\n errorHandlers.push(handler);\n },\n beforeRequest(handler) {\n beforeRequestHandlers.push(handler);\n },\n afterResponse(handler) {\n afterResponseHandlers.push(handler);\n },\n registerCommands(registrar) {\n const registry = {\n add(cmd: PluginCommand) {\n registeredCommands.push(cmd);\n },\n };\n registrar(registry);\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Permission validation\n// ---------------------------------------------------------------------------\n\nconst VALID_PERMISSIONS: ReadonlySet<string> = new Set<PluginPermission>([\n \"read:config\",\n \"write:config\",\n \"read:auth\",\n \"api:read\",\n \"api:write\",\n \"commands:register\",\n \"hooks:beforeCommand\",\n \"hooks:afterCommand\",\n \"hooks:onError\",\n \"hooks:beforeRequest\",\n \"hooks:afterResponse\",\n]);\n\nfunction validatePermissions(permissions: PluginPermission[]): void {\n for (const perm of permissions) {\n if (!VALID_PERMISSIONS.has(perm)) {\n throw new GpcError(\n `Unknown plugin permission: \"${perm}\"`,\n \"PLUGIN_INVALID_PERMISSION\",\n 10,\n `Valid permissions: ${[...VALID_PERMISSIONS].join(\", \")}`,\n );\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Plugin discovery\n// ---------------------------------------------------------------------------\n\nexport interface DiscoverPluginsOptions {\n /** Plugin names from config file */\n configPlugins?: string[];\n\n /** Working directory for node_modules scanning */\n cwd?: string;\n}\n\n/**\n * Discover plugins from multiple sources:\n * 1. Explicit config: gpc.config.ts → plugins: [...]\n * 2. Convention: node_modules/@gpc-cli/plugin-*\n * 3. Convention: node_modules/gpc-plugin-*\n */\nexport async function discoverPlugins(options?: DiscoverPluginsOptions): Promise<GpcPlugin[]> {\n const plugins: GpcPlugin[] = [];\n const seen = new Set<string>();\n\n // Source 1: Explicit config plugins\n if (options?.configPlugins) {\n for (const name of options.configPlugins) {\n if (seen.has(name)) continue;\n try {\n const mod = await import(name);\n const plugin = resolvePlugin(mod);\n if (plugin) {\n plugins.push(plugin);\n seen.add(name);\n }\n } catch {\n // Plugin not found — skip silently\n }\n }\n }\n\n return plugins;\n}\n\n/**\n * Resolve a plugin from a module.\n * Supports: default export, named `plugin` export, or the module itself as a plugin.\n */\nfunction resolvePlugin(mod: unknown): GpcPlugin | undefined {\n if (!mod || typeof mod !== \"object\") return undefined;\n\n const m = mod as Record<string, unknown>;\n\n // Check default export\n if (isPlugin(m[\"default\"])) return m[\"default\"];\n\n // Check named `plugin` export\n if (isPlugin(m[\"plugin\"])) return m[\"plugin\"];\n\n // Check if module itself is a plugin\n if (isPlugin(m)) return m as unknown as GpcPlugin;\n\n return undefined;\n}\n\nfunction isPlugin(obj: unknown): obj is GpcPlugin {\n if (!obj || typeof obj !== \"object\") return false;\n const p = obj as Record<string, unknown>;\n return (\n typeof p[\"name\"] === \"string\" &&\n typeof p[\"version\"] === \"string\" &&\n typeof p[\"register\"] === \"function\"\n );\n}\n","import type { PlayApiClient } from \"@gpc-cli/api\";\n\nexport interface AppInfo {\n packageName: string;\n title?: string;\n defaultLanguage?: string;\n contactEmail?: string;\n}\n\nexport async function getAppInfo(client: PlayApiClient, packageName: string): Promise<AppInfo> {\n // Create an edit to read app details (Google Play requires an edit context)\n const edit = await client.edits.insert(packageName);\n try {\n const details = await client.details.get(packageName, edit.id);\n // Delete the edit since we're only reading\n await client.edits.delete(packageName, edit.id);\n return {\n packageName,\n title: details.title,\n defaultLanguage: details.defaultLanguage,\n contactEmail: details.contactEmail,\n };\n } catch (error) {\n // Clean up edit on failure\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n","import { stat } from \"node:fs/promises\";\nimport type {\n PlayApiClient,\n Release,\n Track,\n ExternallyHostedApk,\n ExternallyHostedApkResponse,\n UploadProgressEvent,\n ResumableUploadOptions,\n} from \"@gpc-cli/api\";\nimport type { AppEdit } from \"@gpc-cli/api\";\nimport { PlayApiError } from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\nimport { validateUploadFile } from \"../utils/file-validation.js\";\n\n/**\n * Retry an edit-based operation once if it fails with 409 Conflict (stale edit).\n * Automatically discards the stale edit and creates a fresh one on retry.\n */\nasync function withRetryOnConflict<T>(\n client: PlayApiClient,\n packageName: string,\n operation: (edit: AppEdit) => Promise<T>,\n): Promise<T> {\n const edit = await client.edits.insert(packageName);\n try {\n return await operation(edit);\n } catch (error) {\n const isConflict = error instanceof PlayApiError && error.statusCode === 409;\n if (!isConflict) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n // Discard stale edit, retry with fresh one\n await client.edits.delete(packageName, edit.id).catch(() => {});\n const freshEdit = await client.edits.insert(packageName);\n try {\n return await operation(freshEdit);\n } catch (retryError) {\n await client.edits.delete(packageName, freshEdit.id).catch(() => {});\n throw retryError;\n }\n }\n}\n\n/** Warn if edit is within 5 minutes of expiry. */\nfunction warnIfEditExpiring(edit: AppEdit): void {\n if (!edit.expiryTimeSeconds) return;\n const expiryMs = Number(edit.expiryTimeSeconds) * 1000;\n const remainingMs = expiryMs - Date.now();\n if (remainingMs < 5 * 60 * 1000 && remainingMs > 0) {\n const minutes = Math.round(remainingMs / 60_000);\n process.emitWarning?.(\n `Edit session expires in ~${minutes} minute${minutes !== 1 ? \"s\" : \"\"}. Long uploads may fail. Consider starting a fresh operation.`,\n \"EditExpiryWarning\",\n );\n }\n}\n\n/**\n * Run an edit-lifecycle operation with automatic retry on expired-edit errors.\n * If the API returns API_EDIT_EXPIRED (FAILED_PRECONDITION), the helper opens a\n * fresh edit and retries the operation exactly once.\n */\nexport async function withFreshEdit<T>(\n client: PlayApiClient,\n packageName: string,\n operation: (editId: string) => Promise<T>,\n): Promise<T> {\n const edit = await client.edits.insert(packageName);\n try {\n return await operation(edit.id);\n } catch (error) {\n if (error instanceof PlayApiError && error.code === \"API_EDIT_EXPIRED\") {\n // Discard stale edit (best effort) and retry with a fresh one\n await client.edits.delete(packageName, edit.id).catch(() => {});\n const freshEdit = await client.edits.insert(packageName);\n try {\n return await operation(freshEdit.id);\n } catch (retryError) {\n await client.edits.delete(packageName, freshEdit.id).catch(() => {});\n throw retryError;\n }\n }\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport interface UploadResult {\n versionCode: number;\n track: string;\n status: string;\n}\n\nexport interface ReleaseStatusResult {\n track: string;\n status: string;\n versionCodes: string[];\n userFraction?: number;\n releaseNotes?: { language: string; text: string }[];\n}\n\nexport interface DryRunUploadResult {\n dryRun: true;\n file: { path: string; valid: boolean; errors: string[]; warnings: string[] };\n track: string;\n currentReleases: { versionCodes: string[]; status: string; userFraction?: number }[];\n plannedRelease: { status: string; userFraction?: number };\n}\n\nexport async function uploadRelease(\n client: PlayApiClient,\n packageName: string,\n filePath: string,\n options: {\n track: string;\n status?: string;\n userFraction?: number;\n releaseNotes?: { language: string; text: string }[];\n releaseName?: string;\n mappingFile?: string;\n dryRun?: boolean;\n onProgress?: (uploaded: number, total: number) => void;\n onUploadProgress?: (event: UploadProgressEvent) => void;\n uploadOptions?: Pick<\n ResumableUploadOptions,\n \"chunkSize\" | \"resumeSessionUri\" | \"maxResumeAttempts\"\n >;\n },\n): Promise<UploadResult | DryRunUploadResult> {\n // Validate file before upload\n const validation = await validateUploadFile(filePath);\n\n if (options.dryRun) {\n const plannedStatus = options.status || (options.userFraction ? \"inProgress\" : \"completed\");\n\n // Fetch current track state without modifying anything\n let currentReleases: DryRunUploadResult[\"currentReleases\"] = [];\n const edit = await client.edits.insert(packageName);\n try {\n const trackData = await client.tracks.get(packageName, edit.id, options.track);\n currentReleases = (trackData.releases || []).map((r) => ({\n versionCodes: r.versionCodes || [],\n status: r.status,\n ...(r.userFraction !== undefined && { userFraction: r.userFraction }),\n }));\n } catch {\n // Track may not exist yet — that's fine for dry-run\n } finally {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n }\n\n return {\n dryRun: true,\n file: {\n path: filePath,\n valid: validation.valid,\n errors: validation.errors,\n warnings: validation.warnings,\n },\n track: options.track,\n currentReleases,\n plannedRelease: {\n status: plannedStatus,\n ...(options.userFraction !== undefined && { userFraction: options.userFraction }),\n },\n };\n }\n\n if (!validation.valid) {\n throw new GpcError(\n `File validation failed:\\n${validation.errors.join(\"\\n\")}`,\n \"RELEASE_INVALID_FILE\",\n 2,\n \"Check that the file is a valid AAB or APK and is not corrupted.\",\n );\n }\n\n // Get file size for progress reporting\n let fileSize = 0;\n try {\n const { size } = await stat(filePath);\n fileSize = size;\n } catch {\n /* ignore — file was validated above */\n }\n\n if (options.onProgress) options.onProgress(0, fileSize);\n\n const edit = await client.edits.insert(packageName);\n warnIfEditExpiring(edit);\n try {\n // Upload the bundle with resumable upload protocol\n const bundle = await client.bundles.upload(packageName, edit.id, filePath, {\n ...options.uploadOptions,\n onProgress: (event) => {\n if (options.onProgress) options.onProgress(event.bytesUploaded, event.totalBytes);\n if (options.onUploadProgress) options.onUploadProgress(event);\n },\n });\n\n // Upload mapping file if provided\n if (options.mappingFile) {\n await client.deobfuscation.upload(\n packageName,\n edit.id,\n bundle.versionCode,\n options.mappingFile,\n );\n }\n\n // Create release and assign to track\n const release: Release = {\n versionCodes: [String(bundle.versionCode)],\n status: (options.status ||\n (options.userFraction ? \"inProgress\" : \"completed\")) as Release[\"status\"],\n ...(options.userFraction && { userFraction: options.userFraction }),\n ...(options.releaseNotes && { releaseNotes: options.releaseNotes }),\n ...(options.releaseName && { name: options.releaseName }),\n };\n\n await client.tracks.update(packageName, edit.id, options.track, release);\n\n // Validate and commit\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n\n return {\n versionCode: bundle.versionCode,\n track: options.track,\n status: release.status,\n };\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function getReleasesStatus(\n client: PlayApiClient,\n packageName: string,\n trackFilter?: string,\n): Promise<ReleaseStatusResult[]> {\n const edit = await client.edits.insert(packageName);\n try {\n const tracks = trackFilter\n ? [await client.tracks.get(packageName, edit.id, trackFilter)]\n : await client.tracks.list(packageName, edit.id);\n\n await client.edits.delete(packageName, edit.id);\n\n const results: ReleaseStatusResult[] = [];\n for (const track of tracks) {\n for (const release of track.releases || []) {\n results.push({\n track: track.track,\n status: release.status,\n versionCodes: release.versionCodes || [],\n userFraction: release.userFraction,\n releaseNotes: release.releaseNotes,\n });\n }\n }\n return results;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function promoteRelease(\n client: PlayApiClient,\n packageName: string,\n fromTrack: string,\n toTrack: string,\n options?: { userFraction?: number; releaseNotes?: { language: string; text: string }[] },\n): Promise<ReleaseStatusResult> {\n // Validate inputs before opening an edit\n if (options?.userFraction && (options.userFraction <= 0 || options.userFraction > 1)) {\n throw new GpcError(\n \"Rollout percentage must be between 0 and 1 (e.g., 0.1 for 10%)\",\n \"RELEASE_INVALID_FRACTION\",\n 2,\n \"Use a decimal value like 0.1 for 10%, 0.5 for 50%, or 1.0 for 100%.\",\n );\n }\n\n return withRetryOnConflict(client, packageName, async (edit) => {\n // Get current release from source track\n const sourceTrack = await client.tracks.get(packageName, edit.id, fromTrack);\n const currentRelease = sourceTrack.releases?.find(\n (r) => r.status === \"completed\" || r.status === \"inProgress\",\n );\n\n if (!currentRelease) {\n throw new GpcError(\n `No active release found on track \"${fromTrack}\"`,\n \"RELEASE_NOT_FOUND\",\n 1,\n `Ensure there is a completed or in-progress release on the \"${fromTrack}\" track before promoting.`,\n );\n }\n\n const release: Release = {\n versionCodes: currentRelease.versionCodes,\n status: (options?.userFraction ? \"inProgress\" : \"completed\") as Release[\"status\"],\n ...(options?.userFraction && { userFraction: options.userFraction }),\n releaseNotes: options?.releaseNotes || currentRelease.releaseNotes || [],\n };\n\n await client.tracks.update(packageName, edit.id, toTrack, release);\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n\n return {\n track: toTrack,\n status: release.status,\n versionCodes: release.versionCodes,\n userFraction: release.userFraction,\n };\n });\n}\n\nexport async function updateRollout(\n client: PlayApiClient,\n packageName: string,\n track: string,\n action: \"increase\" | \"halt\" | \"resume\" | \"complete\",\n userFraction?: number,\n): Promise<ReleaseStatusResult> {\n const edit = await client.edits.insert(packageName);\n try {\n const trackData = await client.tracks.get(packageName, edit.id, track);\n const currentRelease = trackData.releases?.find(\n (r) => r.status === \"inProgress\" || r.status === \"halted\",\n );\n\n if (!currentRelease) {\n throw new GpcError(\n `No active rollout found on track \"${track}\"`,\n \"ROLLOUT_NOT_FOUND\",\n 1,\n `There is no in-progress or halted rollout on the \"${track}\" track. Start a staged rollout first with: gpc releases upload --track ${track} --status inProgress --fraction 0.1`,\n );\n }\n\n let newStatus: string;\n let newFraction: number | undefined;\n\n switch (action) {\n case \"increase\":\n if (!userFraction)\n throw new GpcError(\n \"--to <percentage> is required for rollout increase\",\n \"ROLLOUT_MISSING_FRACTION\",\n 2,\n \"Specify the target rollout percentage with --to, e.g.: gpc rollout increase --to 0.5\",\n );\n if (userFraction <= 0 || userFraction > 1) {\n throw new GpcError(\n \"Rollout percentage must be between 0 and 1 (e.g., 0.1 for 10%)\",\n \"RELEASE_INVALID_FRACTION\",\n 2,\n \"Use a decimal value like 0.1 for 10%, 0.5 for 50%, or 1.0 for 100%.\",\n );\n }\n newStatus = \"inProgress\";\n newFraction = userFraction;\n break;\n case \"halt\":\n newStatus = \"halted\";\n newFraction = currentRelease.userFraction;\n break;\n case \"resume\":\n newStatus = \"inProgress\";\n newFraction = currentRelease.userFraction;\n break;\n case \"complete\":\n newStatus = \"completed\";\n newFraction = undefined;\n break;\n }\n\n const release: Release = {\n versionCodes: currentRelease.versionCodes,\n status: newStatus as Release[\"status\"],\n ...(newFraction !== undefined && { userFraction: newFraction }),\n releaseNotes: currentRelease.releaseNotes || [],\n };\n\n await client.tracks.update(packageName, edit.id, track, release);\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n\n return {\n track,\n status: newStatus,\n versionCodes: release.versionCodes,\n userFraction: newFraction,\n };\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function listTracks(client: PlayApiClient, packageName: string): Promise<Track[]> {\n const edit = await client.edits.insert(packageName);\n try {\n const tracks = await client.tracks.list(packageName, edit.id);\n await client.edits.delete(packageName, edit.id);\n return tracks;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function createTrack(\n client: PlayApiClient,\n packageName: string,\n trackName: string,\n): Promise<Track> {\n if (!trackName || trackName.trim().length === 0) {\n throw new GpcError(\n \"Track name must not be empty\",\n \"TRACK_INVALID_NAME\",\n 2,\n \"Provide a valid custom track name, e.g.: gpc tracks create my-qa-track\",\n );\n }\n\n const edit = await client.edits.insert(packageName);\n try {\n const track = await client.tracks.create(packageName, edit.id, trackName);\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n return track;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function updateTrackConfig(\n client: PlayApiClient,\n packageName: string,\n trackName: string,\n config: Record<string, unknown>,\n): Promise<Track> {\n if (!trackName || trackName.trim().length === 0) {\n throw new GpcError(\n \"Track name must not be empty\",\n \"TRACK_INVALID_NAME\",\n 2,\n \"Provide a valid track name.\",\n );\n }\n\n const edit = await client.edits.insert(packageName);\n try {\n const release: Release = {\n versionCodes: (config[\"versionCodes\"] as string[]) || [],\n status: ((config[\"status\"] as string) || \"completed\") as Release[\"status\"],\n };\n if (config[\"userFraction\"] !== undefined) {\n release.userFraction = config[\"userFraction\"] as number;\n }\n if (config[\"releaseNotes\"]) {\n release.releaseNotes = config[\"releaseNotes\"] as { language: string; text: string }[];\n }\n if (config[\"name\"]) {\n release.name = config[\"name\"] as string;\n }\n\n const track = await client.tracks.update(packageName, edit.id, trackName, release);\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n return track;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\n/**\n * Fetch release notes from the latest active release on a given track.\n * Opens and discards an edit — read-only, no mutations.\n */\nexport async function fetchReleaseNotes(\n client: PlayApiClient,\n packageName: string,\n track: string,\n): Promise<{ language: string; text: string }[]> {\n const edit = await client.edits.insert(packageName);\n try {\n const trackData = await client.tracks.get(packageName, edit.id, track);\n const release =\n trackData.releases?.find((r) => r.status === \"completed\" || r.status === \"inProgress\") ??\n trackData.releases?.[0];\n\n if (!release) {\n throw new GpcError(\n `No release found on track \"${track}\" to copy notes from`,\n \"RELEASE_NOT_FOUND\",\n 1,\n `Ensure there is a release on the \"${track}\" track.`,\n );\n }\n\n return release.releaseNotes ?? [];\n } finally {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n }\n}\n\nexport interface ReleaseDiff {\n field: string;\n track1Value: string;\n track2Value: string;\n}\n\nexport async function diffReleases(\n client: PlayApiClient,\n packageName: string,\n fromTrack: string,\n toTrack: string,\n): Promise<{ fromTrack: string; toTrack: string; diffs: ReleaseDiff[] }> {\n const edit = await client.edits.insert(packageName);\n try {\n const [fromData, toData] = await Promise.all([\n client.tracks.get(packageName, edit.id, fromTrack),\n client.tracks.get(packageName, edit.id, toTrack),\n ]);\n await client.edits.delete(packageName, edit.id);\n\n const fromRelease = fromData.releases?.[0];\n const toRelease = toData.releases?.[0];\n const diffs: ReleaseDiff[] = [];\n\n const fields = [\"versionCodes\", \"status\", \"userFraction\", \"releaseNotes\", \"name\"] as const;\n for (const field of fields) {\n const v1 = fromRelease ? JSON.stringify(fromRelease[field] ?? null) : \"null\";\n const v2 = toRelease ? JSON.stringify(toRelease[field] ?? null) : \"null\";\n if (v1 !== v2) {\n diffs.push({ field, track1Value: v1, track2Value: v2 });\n }\n }\n\n return { fromTrack, toTrack, diffs };\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function uploadExternallyHosted(\n client: PlayApiClient,\n packageName: string,\n data: ExternallyHostedApk,\n): Promise<ExternallyHostedApkResponse> {\n if (!data.externallyHostedUrl) {\n throw new GpcError(\n \"externallyHostedUrl is required\",\n \"EXTERNAL_APK_MISSING_URL\",\n 2,\n \"Provide a valid URL for the externally hosted APK.\",\n );\n }\n\n if (!data.packageName) {\n throw new GpcError(\n \"packageName is required in externally hosted APK data\",\n \"EXTERNAL_APK_MISSING_PACKAGE\",\n 2,\n \"Include the packageName field in the APK configuration.\",\n );\n }\n\n const edit = await client.edits.insert(packageName);\n try {\n const result = await client.apks.addExternallyHosted(packageName, edit.id, data);\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n return result;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n","import { open, stat } from \"node:fs/promises\";\nimport { extname } from \"node:path\";\n\nexport interface FileValidationResult {\n valid: boolean;\n fileType: \"aab\" | \"apk\" | \"unknown\";\n sizeBytes: number;\n errors: string[];\n warnings: string[];\n}\n\n// ZIP magic bytes: PK\\x03\\x04\nconst ZIP_MAGIC = Buffer.from([0x50, 0x4b, 0x03, 0x04]);\n\nconst MAX_APK_SIZE = 1024 * 1024 * 1024; // 1 GB (Google Play API limit)\nconst MAX_AAB_SIZE = 2 * 1024 * 1024 * 1024; // 2 GB (Google Play API limit)\nconst LARGE_FILE_THRESHOLD = 100 * 1024 * 1024; // 100 MB — warn about upload time\n\nexport async function validateUploadFile(filePath: string): Promise<FileValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n // Check extension\n const ext = extname(filePath).toLowerCase();\n let fileType: FileValidationResult[\"fileType\"] = \"unknown\";\n\n if (ext === \".aab\") {\n fileType = \"aab\";\n } else if (ext === \".apk\") {\n fileType = \"apk\";\n } else {\n errors.push(`Unsupported file extension \"${ext}\". Expected .aab or .apk`);\n }\n\n // Check file exists and get size\n let sizeBytes: number;\n try {\n const stats = await stat(filePath);\n sizeBytes = stats.size;\n\n if (sizeBytes === 0) {\n errors.push(\"File is empty (0 bytes)\");\n }\n } catch {\n errors.push(`File not found: ${filePath}`);\n return { valid: false, fileType, sizeBytes: 0, errors, warnings };\n }\n\n // Check size limits\n if (fileType === \"apk\" && sizeBytes > MAX_APK_SIZE) {\n errors.push(\n `APK exceeds 1 GB limit (${formatSize(sizeBytes)}). Consider using AAB format instead.`,\n );\n }\n if (fileType === \"aab\" && sizeBytes > MAX_AAB_SIZE) {\n errors.push(`AAB exceeds 2 GB limit (${formatSize(sizeBytes)}).`);\n }\n\n if (sizeBytes > LARGE_FILE_THRESHOLD && errors.length === 0) {\n warnings.push(\n `Large file (${formatSize(sizeBytes)}). Upload may take a while on slow connections.`,\n );\n }\n\n // Check magic bytes — only read first 4 bytes, not the entire file\n if (sizeBytes > 0) {\n let fh;\n try {\n fh = await open(filePath, \"r\");\n const buf = Buffer.alloc(4);\n await fh.read(buf, 0, 4, 0);\n\n if (!buf.equals(ZIP_MAGIC)) {\n errors.push(\n \"File does not have valid ZIP magic bytes (PK\\\\x03\\\\x04). \" +\n \"Both AAB and APK files must be valid ZIP archives.\",\n );\n }\n } catch {\n errors.push(\"Unable to read file header for validation\");\n } finally {\n await fh?.close();\n }\n }\n\n return {\n valid: errors.length === 0,\n fileType,\n sizeBytes,\n errors,\n warnings,\n };\n}\n\nfunction formatSize(bytes: number): string {\n if (bytes >= 1024 * 1024 * 1024) {\n return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;\n }\n if (bytes >= 1024 * 1024) {\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n }\n if (bytes >= 1024) {\n return `${(bytes / 1024).toFixed(1)} KB`;\n }\n return `${bytes} B`;\n}\n","export const GOOGLE_PLAY_LANGUAGES: string[] = [\n \"af\",\n \"am\",\n \"ar\",\n \"hy-AM\",\n \"az-AZ\",\n \"eu-ES\",\n \"be\",\n \"bn-BD\",\n \"bg\",\n \"my-MM\",\n \"ca\",\n \"zh-HK\",\n \"zh-CN\",\n \"zh-TW\",\n \"hr\",\n \"cs-CZ\",\n \"da-DK\",\n \"nl-NL\",\n \"en-AU\",\n \"en-CA\",\n \"en-IN\",\n \"en-SG\",\n \"en-GB\",\n \"en-US\",\n \"et\",\n \"fil\",\n \"fi-FI\",\n \"fr-FR\",\n \"fr-CA\",\n \"gl-ES\",\n \"ka-GE\",\n \"de-DE\",\n \"el-GR\",\n \"gu\",\n \"iw-IL\",\n \"hi-IN\",\n \"hu-HU\",\n \"is-IS\",\n \"id\",\n \"it-IT\",\n \"ja-JP\",\n \"kn-IN\",\n \"kk\",\n \"km-KH\",\n \"ko-KR\",\n \"ky-KG\",\n \"lo-LA\",\n \"lv\",\n \"lt\",\n \"mk-MK\",\n \"ms\",\n \"ms-MY\",\n \"ml-IN\",\n \"mr-IN\",\n \"mn-MN\",\n \"ne-NP\",\n \"no-NO\",\n \"fa\",\n \"pl-PL\",\n \"pt-BR\",\n \"pt-PT\",\n \"pa\",\n \"ro\",\n \"rm\",\n \"ru-RU\",\n \"sr\",\n \"si-LK\",\n \"sk\",\n \"sl\",\n \"es-419\",\n \"es-ES\",\n \"es-US\",\n \"sw\",\n \"sv-SE\",\n \"ta-IN\",\n \"te-IN\",\n \"th\",\n \"tr-TR\",\n \"uk\",\n \"ur\",\n \"vi\",\n \"zu\",\n];\n\nexport function isValidBcp47(tag: string): boolean {\n return GOOGLE_PLAY_LANGUAGES.includes(tag);\n}\n","import { stat } from \"node:fs/promises\";\nimport { extname } from \"node:path\";\n\nexport interface ImageValidationResult {\n valid: boolean;\n warnings: string[];\n errors: string[];\n}\n\n// Google Play image size limits\nconst IMAGE_SIZE_LIMITS: Record<string, { maxBytes: number; label: string }> = {\n icon: { maxBytes: 1024 * 1024, label: \"1 MB\" },\n featureGraphic: { maxBytes: 1024 * 1024, label: \"1 MB\" },\n tvBanner: { maxBytes: 1024 * 1024, label: \"1 MB\" },\n phoneScreenshots: { maxBytes: 8 * 1024 * 1024, label: \"8 MB\" },\n sevenInchScreenshots: { maxBytes: 8 * 1024 * 1024, label: \"8 MB\" },\n tenInchScreenshots: { maxBytes: 8 * 1024 * 1024, label: \"8 MB\" },\n tvScreenshots: { maxBytes: 8 * 1024 * 1024, label: \"8 MB\" },\n wearScreenshots: { maxBytes: 8 * 1024 * 1024, label: \"8 MB\" },\n};\n\nconst VALID_EXTENSIONS = new Set([\".png\", \".jpg\", \".jpeg\"]);\nconst LARGE_IMAGE_THRESHOLD = 2 * 1024 * 1024; // 2 MB\n\nexport async function validateImage(\n filePath: string,\n imageType?: string,\n): Promise<ImageValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n // Check extension\n const ext = extname(filePath).toLowerCase();\n if (!VALID_EXTENSIONS.has(ext)) {\n errors.push(`Unsupported image format \"${ext}\". Use PNG or JPEG.`);\n }\n\n // Check file exists and size\n let sizeBytes: number;\n try {\n const stats = await stat(filePath);\n sizeBytes = stats.size;\n\n if (sizeBytes === 0) {\n errors.push(\"Image file is empty (0 bytes)\");\n }\n } catch {\n errors.push(`Image file not found: ${filePath}`);\n return { valid: false, errors, warnings };\n }\n\n // Check size limits per image type\n if (imageType && sizeBytes > 0) {\n const limit = IMAGE_SIZE_LIMITS[imageType];\n if (limit && sizeBytes > limit.maxBytes) {\n errors.push(`Image exceeds ${limit.label} limit for ${imageType} (${formatSize(sizeBytes)})`);\n }\n }\n\n // Warn about large images\n if (sizeBytes > LARGE_IMAGE_THRESHOLD && errors.length === 0) {\n warnings.push(\n `Large image (${formatSize(sizeBytes)}). Consider optimizing for faster upload and better store performance.`,\n );\n }\n\n // PNG optimization warning\n if (ext === \".png\" && sizeBytes > 512 * 1024) {\n warnings.push(\n \"PNG file is over 512 KB. Consider compressing with tools like pngquant or optipng.\",\n );\n }\n\n return { valid: errors.length === 0, errors, warnings };\n}\n\nfunction formatSize(bytes: number): string {\n if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n if (bytes >= 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${bytes} B`;\n}\n","import { readFile, writeFile, mkdir, readdir, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { Listing } from \"@gpc-cli/api\";\n\nconst FILE_MAP: Record<string, keyof Omit<Listing, \"language\">> = {\n \"title.txt\": \"title\",\n \"short_description.txt\": \"shortDescription\",\n \"full_description.txt\": \"fullDescription\",\n \"video.txt\": \"video\",\n};\n\nconst FIELD_TO_FILE: Record<string, string> = Object.fromEntries(\n Object.entries(FILE_MAP).map(([file, field]) => [field, file]),\n);\n\nexport interface ListingDiff {\n language: string;\n field: string;\n local: string;\n remote: string;\n}\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function readListingsFromDir(dir: string): Promise<Listing[]> {\n const listings: Listing[] = [];\n\n if (!(await exists(dir))) return listings;\n\n const entries = await readdir(dir);\n // Validate directory names to prevent path traversal\n const SAFE_LANG = /^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8})*$/;\n for (const lang of entries) {\n if (!SAFE_LANG.test(lang)) continue;\n const langDir = join(dir, lang);\n const langStat = await stat(langDir);\n if (!langStat.isDirectory()) continue;\n\n const listing: Listing = {\n language: lang,\n title: \"\",\n shortDescription: \"\",\n fullDescription: \"\",\n };\n\n for (const [fileName, field] of Object.entries(FILE_MAP)) {\n const filePath = join(langDir, fileName);\n if (await exists(filePath)) {\n const content = await readFile(filePath, \"utf-8\");\n (listing as unknown as Record<string, string>)[field] = content.trimEnd();\n }\n }\n\n listings.push(listing);\n }\n\n return listings;\n}\n\nexport async function writeListingsToDir(dir: string, listings: Listing[]): Promise<void> {\n for (const listing of listings) {\n const langDir = join(dir, listing.language);\n await mkdir(langDir, { recursive: true });\n\n for (const [field, fileName] of Object.entries(FIELD_TO_FILE)) {\n const value = (listing as unknown as Record<string, string>)[field];\n if (value !== undefined && value !== \"\") {\n await writeFile(join(langDir, fileName), value + \"\\n\", \"utf-8\");\n }\n }\n }\n}\n\nexport function diffListings(local: Listing[], remote: Listing[]): ListingDiff[] {\n const diffs: ListingDiff[] = [];\n const remoteMap = new Map(remote.map((l) => [l.language, l]));\n const localMap = new Map(local.map((l) => [l.language, l]));\n\n // Check all local listings against remote\n for (const localListing of local) {\n const remoteListing = remoteMap.get(localListing.language);\n for (const [field] of Object.entries(FIELD_TO_FILE)) {\n const localVal = (\n (localListing as unknown as Record<string, string>)[field] ?? \"\"\n ).toString();\n const remoteVal = remoteListing\n ? ((remoteListing as unknown as Record<string, string>)[field] ?? \"\").toString()\n : \"\";\n if (localVal !== remoteVal) {\n diffs.push({\n language: localListing.language,\n field,\n local: localVal,\n remote: remoteVal,\n });\n }\n }\n }\n\n // Check for remote-only languages\n for (const remoteListing of remote) {\n if (!localMap.has(remoteListing.language)) {\n for (const [field] of Object.entries(FIELD_TO_FILE)) {\n const remoteVal = (\n (remoteListing as unknown as Record<string, string>)[field] ?? \"\"\n ).toString();\n if (remoteVal) {\n diffs.push({\n language: remoteListing.language,\n field,\n local: \"\",\n remote: remoteVal,\n });\n }\n }\n }\n }\n\n return diffs;\n}\n","/** Listing text lint and diff utilities. No external deps — pure functions. */\n\nexport interface ListingFieldLimits {\n title: number;\n shortDescription: number;\n fullDescription: number;\n video: number;\n}\n\nexport const DEFAULT_LIMITS: ListingFieldLimits = {\n title: 30,\n shortDescription: 80,\n fullDescription: 4000,\n video: 256,\n};\n\nexport interface FieldLintResult {\n field: string;\n chars: number;\n limit: number;\n pct: number;\n status: \"ok\" | \"warn\" | \"over\";\n}\n\nexport interface ListingLintResult {\n language: string;\n fields: FieldLintResult[];\n valid: boolean;\n}\n\nexport interface LintableFields {\n title?: string;\n shortDescription?: string;\n fullDescription?: string;\n video?: string;\n [key: string]: string | undefined;\n}\n\n/** Lint a single listing's fields against character limits. */\nexport function lintListing(\n language: string,\n fields: LintableFields,\n limits: ListingFieldLimits = DEFAULT_LIMITS,\n): ListingLintResult {\n const fieldResults: FieldLintResult[] = [];\n\n for (const [field, limit] of Object.entries(limits) as [keyof ListingFieldLimits, number][]) {\n const value = fields[field] ?? \"\";\n const chars = [...value].length; // Unicode-aware char count\n const pct = Math.round((chars / limit) * 100);\n let status: FieldLintResult[\"status\"] = \"ok\";\n if (chars > limit) status = \"over\";\n else if (pct >= 80) status = \"warn\";\n fieldResults.push({ field, chars, limit, pct, status });\n }\n\n const valid = fieldResults.every((r) => r.status !== \"over\");\n return { language, fields: fieldResults, valid };\n}\n\n/** Lint multiple listings. */\nexport function lintListings(\n listings: { language: string; fields: LintableFields }[],\n limits?: ListingFieldLimits,\n): ListingLintResult[] {\n return listings.map((l) => lintListing(l.language, l.fields, limits));\n}\n\n// ---------------------------------------------------------------------------\n// Word-level diff (LCS-based)\n// ---------------------------------------------------------------------------\n\nexport interface DiffToken {\n text: string;\n type: \"equal\" | \"insert\" | \"delete\";\n}\n\nfunction tokenize(text: string): string[] {\n return text.split(/(\\s+)/);\n}\n\n/** Compute word-level LCS diff between two strings. */\nexport function wordDiff(before: string, after: string): DiffToken[] {\n const aTokens = tokenize(before);\n const bTokens = tokenize(after);\n const m = aTokens.length;\n const n = bTokens.length;\n\n // LCS DP\n const dp: number[][] = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0) as number[]);\n const cell = (r: number, c: number): number => dp[r]?.[c] ?? 0;\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n (dp[i] as number[])[j] =\n aTokens[i - 1] === bTokens[j - 1]\n ? cell(i - 1, j - 1) + 1\n : Math.max(cell(i - 1, j), cell(i, j - 1));\n }\n }\n\n // Backtrack\n const result: DiffToken[] = [];\n let i = m,\n j = n;\n while (i > 0 || j > 0) {\n if (i > 0 && j > 0 && aTokens[i - 1] === bTokens[j - 1]) {\n result.unshift({ text: aTokens[i - 1] ?? \"\", type: \"equal\" });\n i--;\n j--;\n } else if (j > 0 && (i === 0 || cell(i, j - 1) >= cell(i - 1, j))) {\n result.unshift({ text: bTokens[j - 1] ?? \"\", type: \"insert\" });\n j--;\n } else {\n result.unshift({ text: aTokens[i - 1] ?? \"\", type: \"delete\" });\n i--;\n }\n }\n return result;\n}\n\n/** Format a word diff as an inline string with +/- markers. */\nexport function formatWordDiff(diff: DiffToken[]): string {\n return diff\n .map((t) => {\n if (t.type === \"equal\") return t.text;\n if (t.type === \"insert\") return `[+${t.text}]`;\n return `[-${t.text}]`;\n })\n .join(\"\");\n}\n","import type {\n PlayApiClient,\n Listing,\n Image,\n ImageType,\n AppDetails,\n CountryAvailability,\n} from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\nimport { isValidBcp47 } from \"../utils/bcp47.js\";\nimport { validateImage } from \"../utils/image-validation.js\";\nimport { readListingsFromDir, writeListingsToDir, diffListings } from \"../utils/fastlane.js\";\nimport type { ListingDiff } from \"../utils/fastlane.js\";\nimport { lintListings, wordDiff, formatWordDiff } from \"../utils/listing-text.js\";\nimport type { ListingLintResult } from \"../utils/listing-text.js\";\n\nexport interface ListingsResult {\n listings: Listing[];\n}\n\nexport interface PushResult {\n updated: number;\n languages: string[];\n}\n\nexport interface DryRunResult {\n diffs: ListingDiff[];\n}\n\nfunction validateLanguage(lang: string): void {\n if (!isValidBcp47(lang)) {\n throw new GpcError(\n `Invalid language tag \"${lang}\". Must be a valid Google Play BCP 47 code.`,\n \"LISTING_INVALID_LANGUAGE\",\n 2,\n \"Use a valid BCP 47 language code such as en-US, de-DE, or ja-JP. See the Google Play Console for supported language codes.\",\n );\n }\n}\n\nexport async function getListings(\n client: PlayApiClient,\n packageName: string,\n language?: string,\n): Promise<Listing[]> {\n const edit = await client.edits.insert(packageName);\n try {\n let listings: Listing[];\n if (language) {\n validateLanguage(language);\n const listing = await client.listings.get(packageName, edit.id, language);\n listings = [listing];\n } else {\n listings = await client.listings.list(packageName, edit.id);\n }\n await client.edits.delete(packageName, edit.id);\n return listings;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function updateListing(\n client: PlayApiClient,\n packageName: string,\n language: string,\n data: Partial<Omit<Listing, \"language\">>,\n): Promise<Listing> {\n validateLanguage(language);\n const edit = await client.edits.insert(packageName);\n try {\n const listing = await client.listings.patch(packageName, edit.id, language, data);\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n return listing;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function deleteListing(\n client: PlayApiClient,\n packageName: string,\n language: string,\n): Promise<void> {\n validateLanguage(language);\n const edit = await client.edits.insert(packageName);\n try {\n await client.listings.delete(packageName, edit.id, language);\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function pullListings(\n client: PlayApiClient,\n packageName: string,\n dir: string,\n): Promise<ListingsResult> {\n const edit = await client.edits.insert(packageName);\n try {\n const listings = await client.listings.list(packageName, edit.id);\n await client.edits.delete(packageName, edit.id);\n await writeListingsToDir(dir, listings);\n return { listings };\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\n/** Lint local listing directory against Play Store character limits (no API call). */\nexport async function lintLocalListings(dir: string): Promise<ListingLintResult[]> {\n const localListings = await readListingsFromDir(dir);\n return lintListings(\n localListings.map((l) => ({\n language: l.language,\n fields: {\n title: l.title,\n shortDescription: l.shortDescription,\n fullDescription: l.fullDescription,\n video: l.video,\n },\n })),\n );\n}\n\n/** Analyze live Play Store listings for character limit compliance (requires API). */\nexport async function analyzeRemoteListings(\n client: PlayApiClient,\n packageName: string,\n options?: { expectedLocales?: string[] },\n): Promise<{ results: ListingLintResult[]; missingLocales?: string[] }> {\n const listings = await getListings(client, packageName);\n\n const results = lintListings(\n listings.map((l) => ({\n language: l.language,\n fields: {\n title: l.title,\n shortDescription: l.shortDescription,\n fullDescription: l.fullDescription,\n video: (l as unknown as Record<string, unknown>)[\"video\"] as string | undefined,\n },\n })),\n );\n\n let missingLocales: string[] | undefined;\n if (options?.expectedLocales) {\n const present = new Set(listings.map((l) => l.language));\n missingLocales = options.expectedLocales.filter((loc) => !present.has(loc));\n }\n\n return { results, missingLocales };\n}\n\n/** Enhanced diff: word-level inline diff for fullDescription, optional language filter. */\nexport async function diffListingsEnhanced(\n client: PlayApiClient,\n packageName: string,\n dir: string,\n options?: { lang?: string; wordLevel?: boolean },\n): Promise<ListingDiff[]> {\n const allDiffs = await diffListingsCommand(client, packageName, dir);\n let result = allDiffs;\n if (options?.lang) {\n result = allDiffs.filter((d) => d.language === options.lang);\n }\n if (options?.wordLevel) {\n return result.map((d) => {\n if (d.field === \"fullDescription\" && d.local && d.remote) {\n const diff = wordDiff(d.remote, d.local);\n return { ...d, diffSummary: formatWordDiff(diff) };\n }\n return d;\n });\n }\n return result;\n}\n\nexport async function pushListings(\n client: PlayApiClient,\n packageName: string,\n dir: string,\n options?: { dryRun?: boolean; force?: boolean },\n): Promise<PushResult | DryRunResult> {\n const localListings = await readListingsFromDir(dir);\n\n if (localListings.length === 0) {\n throw new GpcError(\n `No listings found in directory \"${dir}\"`,\n \"LISTING_DIR_EMPTY\",\n 1,\n `The directory must contain subdirectories named by language code (e.g., en-US/) with listing metadata files. Pull existing listings first with: gpc listings pull --dir \"${dir}\"`,\n );\n }\n\n // Validate all languages\n for (const listing of localListings) {\n validateLanguage(listing.language);\n }\n\n // Preflight lint: block push if any field exceeds limits (unless --force)\n if (!options?.force) {\n const lintResults = lintListings(\n localListings.map((l) => ({\n language: l.language,\n fields: {\n title: l.title,\n shortDescription: l.shortDescription,\n fullDescription: l.fullDescription,\n video: (l as unknown as Record<string, unknown>)[\"video\"] as string | undefined,\n },\n })),\n );\n const overLimit = lintResults.filter((r) => !r.valid);\n if (overLimit.length > 0) {\n const details = overLimit\n .map((r) => {\n const over = r.fields.filter((f) => f.status === \"over\");\n return `${r.language}: ${over.map((f) => `${f.field} (${f.chars}/${f.limit})`).join(\", \")}`;\n })\n .join(\"\\n\");\n throw new GpcError(\n `Listing push blocked: field(s) exceed character limits:\\n${details}`,\n \"LISTING_CHAR_LIMIT_EXCEEDED\",\n 1,\n \"Fix the character limit violations listed above, or use --force to push anyway.\",\n );\n }\n }\n\n const edit = await client.edits.insert(packageName);\n try {\n if (options?.dryRun) {\n const remoteListings = await client.listings.list(packageName, edit.id);\n await client.edits.delete(packageName, edit.id);\n const diffs = diffListings(localListings, remoteListings);\n return { diffs };\n }\n\n for (const listing of localListings) {\n const { language, ...data } = listing;\n await client.listings.update(packageName, edit.id, language, data);\n }\n\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n\n return {\n updated: localListings.length,\n languages: localListings.map((l) => l.language),\n };\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function listImages(\n client: PlayApiClient,\n packageName: string,\n language: string,\n imageType: ImageType,\n): Promise<Image[]> {\n validateLanguage(language);\n const edit = await client.edits.insert(packageName);\n try {\n const images = await client.images.list(packageName, edit.id, language, imageType);\n await client.edits.delete(packageName, edit.id);\n return images;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function uploadImage(\n client: PlayApiClient,\n packageName: string,\n language: string,\n imageType: ImageType,\n filePath: string,\n): Promise<Image> {\n validateLanguage(language);\n\n // Validate image before upload\n const imageCheck = await validateImage(filePath, imageType);\n if (!imageCheck.valid) {\n throw new GpcError(\n `Image validation failed: ${imageCheck.errors.join(\"; \")}`,\n \"IMAGE_INVALID\",\n 2,\n \"Check image dimensions, file size, and format. Google Play requires PNG or JPEG images within specific size limits per image type.\",\n );\n }\n for (const w of imageCheck.warnings) {\n process.emitWarning?.(w, \"ImageUploadWarning\");\n }\n\n const edit = await client.edits.insert(packageName);\n try {\n const image = await client.images.upload(packageName, edit.id, language, imageType, filePath);\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n return image;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function deleteImage(\n client: PlayApiClient,\n packageName: string,\n language: string,\n imageType: ImageType,\n imageId: string,\n): Promise<void> {\n validateLanguage(language);\n const edit = await client.edits.insert(packageName);\n try {\n await client.images.delete(packageName, edit.id, language, imageType, imageId);\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function diffListingsCommand(\n client: PlayApiClient,\n packageName: string,\n dir: string,\n): Promise<ListingDiff[]> {\n const localListings = await readListingsFromDir(dir);\n\n const edit = await client.edits.insert(packageName);\n try {\n const remoteListings = await client.listings.list(packageName, edit.id);\n await client.edits.delete(packageName, edit.id);\n return diffListings(localListings, remoteListings);\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function getCountryAvailability(\n client: PlayApiClient,\n packageName: string,\n track: string,\n): Promise<CountryAvailability> {\n const edit = await client.edits.insert(packageName);\n try {\n const availability = await client.countryAvailability.get(packageName, edit.id, track);\n await client.edits.delete(packageName, edit.id);\n return availability;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport interface ExportImagesOptions {\n lang?: string;\n type?: ImageType;\n}\n\nexport interface ExportImagesSummary {\n languages: number;\n images: number;\n totalSize: number;\n}\n\nconst ALL_IMAGE_TYPES: ImageType[] = [\n \"phoneScreenshots\",\n \"sevenInchScreenshots\",\n \"tenInchScreenshots\",\n \"tvScreenshots\",\n \"wearScreenshots\",\n \"icon\",\n \"featureGraphic\",\n \"tvBanner\",\n];\n\nexport async function exportImages(\n client: PlayApiClient,\n packageName: string,\n dir: string,\n options?: ExportImagesOptions,\n): Promise<ExportImagesSummary> {\n const { mkdir, writeFile } = await import(\"node:fs/promises\");\n const { join } = await import(\"node:path\");\n\n const edit = await client.edits.insert(packageName);\n try {\n // Determine languages\n let languages: string[];\n if (options?.lang) {\n validateLanguage(options.lang);\n languages = [options.lang];\n } else {\n const listings = await client.listings.list(packageName, edit.id);\n languages = listings.map((l) => l.language);\n }\n\n const imageTypes: ImageType[] = options?.type ? [options.type] : ALL_IMAGE_TYPES;\n\n let totalImages = 0;\n let totalSize = 0;\n\n // Collect all download tasks\n const tasks: Array<{ language: string; imageType: ImageType; url: string; index: number }> = [];\n\n for (const language of languages) {\n for (const imageType of imageTypes) {\n const images = await client.images.list(packageName, edit.id, language, imageType);\n for (let i = 0; i < images.length; i++) {\n const img = images[i];\n if (img && img.url) {\n tasks.push({ language, imageType, url: img.url, index: i + 1 });\n }\n }\n }\n }\n\n // Process downloads with concurrency limit of 5\n const concurrency = 5;\n for (let i = 0; i < tasks.length; i += concurrency) {\n const batch = tasks.slice(i, i + concurrency);\n const results = await Promise.all(\n batch.map(async (task) => {\n const dirPath = join(dir, task.language, task.imageType);\n await mkdir(dirPath, { recursive: true });\n\n const response = await fetch(task.url);\n if (!response.ok) {\n throw new GpcError(\n `Failed to download image: HTTP ${response.status} for ${task.imageType} (${task.language})`,\n \"LISTINGS_IMAGE_DOWNLOAD_FAILED\",\n 4,\n \"Check that the image URL is still valid. Re-run the export to retry.\",\n );\n }\n const buffer = Buffer.from(await response.arrayBuffer());\n const filePath = join(dirPath, `${task.index}.png`);\n await writeFile(filePath, buffer);\n\n return buffer.length;\n }),\n );\n\n for (const size of results) {\n totalImages++;\n totalSize += size;\n }\n }\n\n await client.edits.delete(packageName, edit.id);\n\n return {\n languages: languages.length,\n images: totalImages,\n totalSize,\n };\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function updateAppDetails(\n client: PlayApiClient,\n packageName: string,\n details: Partial<AppDetails>,\n): Promise<AppDetails> {\n const edit = await client.edits.insert(packageName);\n try {\n const result = await client.details.patch(packageName, edit.id, details);\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n return result;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n","import { readdir, readFile, writeFile, mkdir, access } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport interface FastlaneDetection {\n hasFastfile: boolean;\n hasAppfile: boolean;\n hasMetadata: boolean;\n hasGemfile: boolean;\n packageName?: string;\n jsonKeyPath?: string;\n lanes: FastlaneLane[];\n metadataLanguages: string[];\n parseWarnings: string[];\n}\n\nexport interface FastlaneLane {\n name: string;\n actions: string[];\n gpcEquivalent?: string;\n}\n\nexport interface MigrationResult {\n config: Record<string, unknown>;\n checklist: string[];\n warnings: string[];\n}\n\n// Ruby constructs that confuse the lane-end regex\nconst COMPLEX_RUBY_RE = /\\b(begin|rescue|ensure|if |unless |case |while |until |for )\\b/;\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function detectFastlane(cwd: string): Promise<FastlaneDetection> {\n const result: FastlaneDetection = {\n hasFastfile: false,\n hasAppfile: false,\n hasMetadata: false,\n hasGemfile: false,\n lanes: [],\n metadataLanguages: [],\n parseWarnings: [],\n };\n\n // Check for fastlane directory or root-level files\n const fastlaneDir = join(cwd, \"fastlane\");\n const hasFastlaneDir = await fileExists(fastlaneDir);\n\n const fastfilePath = hasFastlaneDir ? join(fastlaneDir, \"Fastfile\") : join(cwd, \"Fastfile\");\n const appfilePath = hasFastlaneDir ? join(fastlaneDir, \"Appfile\") : join(cwd, \"Appfile\");\n\n result.hasFastfile = await fileExists(fastfilePath);\n result.hasAppfile = await fileExists(appfilePath);\n result.hasGemfile = await fileExists(join(cwd, \"Gemfile\"));\n\n // Check for metadata directory\n const metadataDir = hasFastlaneDir\n ? join(fastlaneDir, \"metadata\", \"android\")\n : join(cwd, \"metadata\", \"android\");\n\n result.hasMetadata = await fileExists(metadataDir);\n\n if (result.hasMetadata) {\n try {\n const entries = await readdir(metadataDir, { withFileTypes: true });\n result.metadataLanguages = entries.filter((e) => e.isDirectory()).map((e) => e.name);\n } catch {\n result.parseWarnings.push(\"Could not read metadata directory — check permissions\");\n }\n }\n\n // Parse Fastfile if present\n if (result.hasFastfile) {\n try {\n const content = await readFile(fastfilePath, \"utf-8\");\n result.lanes = parseFastfile(content);\n\n // Warn if the Fastfile contains complex Ruby that may have been misread\n if (COMPLEX_RUBY_RE.test(content)) {\n result.parseWarnings.push(\n \"Fastfile contains complex Ruby constructs (begin/rescue/if/unless/case). \" +\n \"Lane detection may be incomplete — review MIGRATION.md and adjust manually.\",\n );\n }\n } catch {\n result.parseWarnings.push(\"Could not read Fastfile — check permissions\");\n }\n }\n\n // Parse Appfile if present\n if (result.hasAppfile) {\n try {\n const content = await readFile(appfilePath, \"utf-8\");\n const parsed = parseAppfile(content);\n result.packageName = parsed.packageName;\n result.jsonKeyPath = parsed.jsonKeyPath;\n } catch {\n result.parseWarnings.push(\"Could not read Appfile — check permissions\");\n }\n }\n\n return result;\n}\n\nexport function parseFastfile(content: string): FastlaneLane[] {\n const lanes: FastlaneLane[] = [];\n // Match lane blocks: lane :name do ... end\n const laneRegex = /lane\\s+:(\\w+)\\s+do([\\s\\S]*?)(?=\\bend\\b)/g;\n let match: RegExpExecArray | null;\n\n while ((match = laneRegex.exec(content)) !== null) {\n const name = match[1] ?? \"\";\n const body = match[2] ?? \"\";\n const actions: string[] = [];\n\n // Extract action calls\n const actionRegex =\n /\\b(supply|upload_to_play_store|capture_android_screenshots|deliver|gradle)\\b/g;\n let actionMatch: RegExpExecArray | null;\n while ((actionMatch = actionRegex.exec(body)) !== null) {\n const action = actionMatch[1] ?? \"\";\n if (!actions.includes(action)) {\n actions.push(action);\n }\n }\n\n // Determine GPC equivalent\n const gpcEquivalent = mapLaneToGpc(name, actions, body);\n\n lanes.push({ name, actions, gpcEquivalent });\n }\n\n return lanes;\n}\n\nfunction mapLaneToGpc(name: string, actions: string[], body: string): string | undefined {\n if (actions.includes(\"upload_to_play_store\") || actions.includes(\"supply\")) {\n const trackMatch = body.match(/track\\s*:\\s*[\"'](\\w+)[\"']/);\n const rolloutMatch = body.match(/rollout\\s*:\\s*[\"']?([\\d.]+)[\"']?/);\n\n if (rolloutMatch) {\n const raw = parseFloat(rolloutMatch[1] ?? \"0\");\n // Fastlane uses 0.0–1.0; convert to whole percentage for gpc\n const pct = raw > 1 ? Math.round(raw) : Math.round(raw * 100);\n return `gpc releases upload --rollout ${pct}${trackMatch ? ` --track ${trackMatch[1]}` : \"\"}`;\n }\n\n if (trackMatch) {\n return `gpc releases upload --track ${trackMatch[1]}`;\n }\n\n // Metadata-only supply\n if (body.match(/skip_upload_apk\\s*:\\s*true/) || body.match(/skip_upload_aab\\s*:\\s*true/)) {\n return \"gpc listings push\";\n }\n\n return \"gpc releases upload\";\n }\n\n if (actions.includes(\"capture_android_screenshots\")) {\n return undefined; // No equivalent\n }\n\n return undefined;\n}\n\nexport function parseAppfile(content: string): { packageName?: string; jsonKeyPath?: string } {\n const result: { packageName?: string; jsonKeyPath?: string } = {};\n\n // Match package_name(\"com.example.app\") or package_name \"com.example.app\"\n const pkgMatch = content.match(/package_name\\s*\\(?\\s*[\"']([^\"']+)[\"']\\s*\\)?/);\n if (pkgMatch) {\n result.packageName = pkgMatch[1];\n }\n\n // Match json_key_file(\"path/to/key.json\") or json_key_file \"path/to/key.json\"\n const keyMatch = content.match(/json_key_file\\s*\\(?\\s*[\"']([^\"']+)[\"']\\s*\\)?/);\n if (keyMatch) {\n result.jsonKeyPath = keyMatch[1];\n }\n\n return result;\n}\n\nexport function generateMigrationPlan(detection: FastlaneDetection): MigrationResult {\n const config: Record<string, unknown> = {};\n const checklist: string[] = [];\n const warnings: string[] = [...detection.parseWarnings];\n\n // Set package name if detected\n if (detection.packageName) {\n config[\"app\"] = detection.packageName;\n } else {\n checklist.push(\"Set your package name: gpc config set app <package-name>\");\n }\n\n // Set auth config if key path detected\n if (detection.jsonKeyPath) {\n config[\"auth\"] = { serviceAccount: detection.jsonKeyPath };\n } else {\n checklist.push(\"Configure authentication: gpc auth login\");\n }\n\n // Lane mappings\n for (const lane of detection.lanes) {\n if (lane.gpcEquivalent) {\n checklist.push(`Replace Fastlane lane \"${lane.name}\" with: ${lane.gpcEquivalent} <your.aab>`);\n }\n\n if (lane.actions.includes(\"capture_android_screenshots\")) {\n warnings.push(\n `Lane \"${lane.name}\" uses capture_android_screenshots which has no GPC equivalent. ` +\n \"Use a separate screenshot tool or check gpc plugins list for community plugins.\",\n );\n }\n\n // Lanes with no known action and no GPC equivalent\n if (\n lane.actions.length === 0 ||\n (lane.gpcEquivalent === undefined && !lane.actions.includes(\"capture_android_screenshots\"))\n ) {\n warnings.push(\n `Lane \"${lane.name}\" has no automatic GPC equivalent. ` +\n \"Check `gpc plugins list` or the plugin SDK docs to build a custom command.\",\n );\n }\n }\n\n // Metadata migration\n if (detection.hasMetadata && detection.metadataLanguages.length > 0) {\n const langs = detection.metadataLanguages.slice(0, 3).join(\", \");\n const more =\n detection.metadataLanguages.length > 3\n ? ` (+${detection.metadataLanguages.length - 3} more)`\n : \"\";\n checklist.push(\n `Pull current metadata for ${detection.metadataLanguages.length} language(s) (${langs}${more}): gpc listings pull --dir fastlane/metadata/android`,\n );\n checklist.push(\n \"Review pulled metadata, then push back: gpc listings push --dir fastlane/metadata/android\",\n );\n }\n\n // General checklist items\n checklist.push(\"Run gpc doctor to verify your setup\");\n checklist.push(\"Test each command with --dry-run before making real changes\");\n\n if (detection.hasGemfile) {\n checklist.push(\"Remove Fastlane from your Gemfile once migration is complete\");\n }\n\n // CI/CD reminder\n if (\n detection.lanes.some(\n (l) => l.actions.includes(\"supply\") || l.actions.includes(\"upload_to_play_store\"),\n )\n ) {\n checklist.push(\"Update CI/CD pipelines to call gpc commands instead of Fastlane lanes\");\n }\n\n return { config, checklist, warnings };\n}\n\nexport async function writeMigrationOutput(\n result: MigrationResult,\n dir: string,\n): Promise<string[]> {\n await mkdir(dir, { recursive: true });\n const files: string[] = [];\n\n // Write .gpcrc.json only if we have something meaningful to put in it\n if (Object.keys(result.config).length > 0) {\n const configPath = join(dir, \".gpcrc.json\");\n await writeFile(configPath, JSON.stringify(result.config, null, 2) + \"\\n\", \"utf-8\");\n files.push(configPath);\n }\n\n // Write MIGRATION.md\n const migrationPath = join(dir, \"MIGRATION.md\");\n const lines: string[] = [\n \"# Fastlane to GPC Migration\",\n \"\",\n \"Generated by `gpc migrate fastlane`. Review and adjust before applying.\",\n \"\",\n \"## Migration Checklist\",\n \"\",\n ];\n\n for (const item of result.checklist) {\n lines.push(`- [ ] ${item}`);\n }\n\n if (result.warnings.length > 0) {\n lines.push(\"\");\n lines.push(\"## Warnings\");\n lines.push(\"\");\n for (const warning of result.warnings) {\n lines.push(`> ⚠ ${warning}`);\n }\n }\n\n lines.push(\"\");\n lines.push(\"## Quick Reference\");\n lines.push(\"\");\n lines.push(\"| Fastlane | GPC |\");\n lines.push(\"|----------|-----|\");\n lines.push(\"| `fastlane supply` | `gpc releases upload` / `gpc listings push` |\");\n lines.push(\"| `upload_to_play_store` | `gpc releases upload` |\");\n lines.push('| `supply(track: \"internal\")` | `gpc releases upload --track internal` |');\n lines.push('| `supply(rollout: \"0.1\")` | `gpc releases upload --rollout 10` |');\n lines.push(\"| `supply(skip_upload_aab: true)` | `gpc listings push` |\");\n lines.push(\"| `capture_android_screenshots` | No equivalent — use separate tool |\");\n lines.push(\"\");\n lines.push(\n \"See the full migration guide: https://yasserstudio.github.io/gpc/migration/from-fastlane\",\n );\n lines.push(\"\");\n\n await writeFile(migrationPath, lines.join(\"\\n\"), \"utf-8\");\n files.push(migrationPath);\n\n return files;\n}\n","import { GpcError } from \"../errors.js\";\nimport { isValidBcp47 } from \"./bcp47.js\";\n\nconst PACKAGE_NAME_RE = /^[a-zA-Z][a-zA-Z0-9_]*(\\.[a-zA-Z][a-zA-Z0-9_]*){1,}$/;\nconst SKU_RE = /^[a-zA-Z0-9._]+$/;\nconst TRACK_NAMES = [\"internal\", \"alpha\", \"beta\", \"production\"];\nconst CUSTOM_TRACK_RE = /^[a-zA-Z0-9\\-_]+$/;\n\nexport function validatePackageName(name: string): void {\n if (!name || !PACKAGE_NAME_RE.test(name)) {\n throw new GpcError(\n `Invalid package name: \"${name}\"`,\n \"INVALID_PACKAGE_NAME\",\n 2,\n \"Package name must be a valid Android application ID (e.g., com.example.myapp)\",\n );\n }\n}\n\nexport function validateVersionCode(code: string | number): void {\n const num = typeof code === \"string\" ? parseInt(code, 10) : code;\n if (!Number.isInteger(num) || num < 1) {\n throw new GpcError(\n `Invalid version code: \"${code}\"`,\n \"INVALID_VERSION_CODE\",\n 2,\n \"Version code must be a positive integer (e.g., 142)\",\n );\n }\n}\n\nexport function validateLanguageCode(code: string): void {\n if (!code || !isValidBcp47(code)) {\n throw new GpcError(\n `Invalid language code: \"${code}\"`,\n \"INVALID_LANGUAGE_CODE\",\n 2,\n \"Language code must be a valid BCP-47 tag supported by Google Play (e.g., en-US, ja-JP, fr-FR)\",\n );\n }\n}\n\nexport function validateTrackName(name: string): void {\n if (!name) {\n throw new GpcError(\n \"Track name is required\",\n \"INVALID_TRACK_NAME\",\n 2,\n \"Specify a track: internal, alpha, beta, production, or a custom track name\",\n );\n }\n if (!TRACK_NAMES.includes(name) && !CUSTOM_TRACK_RE.test(name)) {\n throw new GpcError(\n `Invalid track name: \"${name}\"`,\n \"INVALID_TRACK_NAME\",\n 2,\n `Valid tracks: ${TRACK_NAMES.join(\", \")}, or a custom track matching [a-zA-Z0-9-_]+`,\n );\n }\n}\n\nexport function validateSku(sku: string): void {\n if (!sku || !SKU_RE.test(sku)) {\n throw new GpcError(\n `Invalid product ID (SKU): \"${sku}\"`,\n \"INVALID_SKU\",\n 2,\n \"Product ID must contain only letters, numbers, dots, and underscores (e.g., premium_upgrade)\",\n );\n }\n}\n","import { readdir, readFile, stat } from \"node:fs/promises\";\nimport { extname, basename, join } from \"node:path\";\nimport { GpcError } from \"../errors.js\";\n\nexport interface ReleaseNote {\n language: string;\n text: string;\n}\n\nexport interface ReleaseNotesValidation {\n valid: boolean;\n errors: string[];\n warnings: string[];\n}\n\nconst MAX_NOTES_LENGTH = 500;\n\nexport async function readReleaseNotesFromDir(dir: string): Promise<ReleaseNote[]> {\n let entries: string[];\n try {\n entries = await readdir(dir);\n } catch {\n throw new GpcError(\n `Release notes directory not found: ${dir}`,\n \"RELEASE_NOTES_DIR_NOT_FOUND\",\n 1,\n `Create the directory and add .txt files named by language code (e.g., en-US.txt). Path: ${dir}`,\n );\n }\n\n const notes: ReleaseNote[] = [];\n\n for (const entry of entries) {\n if (extname(entry) !== \".txt\") continue;\n\n const language = basename(entry, \".txt\");\n const filePath = join(dir, entry);\n\n const stats = await stat(filePath);\n if (!stats.isFile()) continue;\n\n const text = (await readFile(filePath, \"utf-8\")).trim();\n if (text.length === 0) continue;\n\n notes.push({ language, text });\n }\n\n return notes;\n}\n\nexport function validateReleaseNotes(notes: ReleaseNote[]): ReleaseNotesValidation {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n const seen = new Set<string>();\n for (const note of notes) {\n if (seen.has(note.language)) {\n errors.push(`Duplicate language code: ${note.language}`);\n }\n seen.add(note.language);\n\n if (note.text.length > MAX_NOTES_LENGTH) {\n warnings.push(\n `Release notes for \"${note.language}\" are ${note.text.length} chars (max ${MAX_NOTES_LENGTH}) — Google Play will reject notes exceeding this limit`,\n );\n }\n }\n\n return { valid: errors.length === 0, errors, warnings };\n}\n","import { stat } from \"node:fs/promises\";\nimport { validateUploadFile } from \"../utils/file-validation.js\";\nimport { readReleaseNotesFromDir, validateReleaseNotes } from \"../utils/release-notes.js\";\n\nexport interface ValidateOptions {\n filePath: string;\n mappingFile?: string;\n track?: string;\n notes?: { language: string; text: string }[];\n notesDir?: string;\n}\n\nexport interface ValidateCheck {\n name: string;\n passed: boolean;\n message: string;\n}\n\nexport interface ValidateResult {\n valid: boolean;\n checks: ValidateCheck[];\n warnings: string[];\n}\n\nconst STANDARD_TRACKS = new Set([\n \"internal\",\n \"alpha\",\n \"beta\",\n \"production\",\n // Form factor tracks\n \"wear:internal\",\n \"wear:alpha\",\n \"wear:beta\",\n \"wear:production\",\n \"automotive:internal\",\n \"automotive:alpha\",\n \"automotive:beta\",\n \"automotive:production\",\n \"tv:internal\",\n \"tv:alpha\",\n \"tv:beta\",\n \"tv:production\",\n \"android_xr:internal\",\n \"android_xr:alpha\",\n \"android_xr:beta\",\n \"android_xr:production\",\n]);\nconst TRACK_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_:-]*$/;\n\nexport async function validatePreSubmission(options: ValidateOptions): Promise<ValidateResult> {\n const checks: ValidateCheck[] = [];\n\n const resultWarnings: string[] = [];\n\n // 1. File validation\n const fileResult = await validateUploadFile(options.filePath);\n checks.push({\n name: \"file\",\n passed: fileResult.valid,\n message: fileResult.valid\n ? `Valid ${fileResult.fileType.toUpperCase()} (${formatSize(fileResult.sizeBytes)})`\n : fileResult.errors.join(\"; \"),\n });\n // Surface file validation warnings (e.g. large file upload time notice)\n for (const w of fileResult.warnings) {\n resultWarnings.push(w);\n }\n\n // 2. Mapping file\n if (options.mappingFile) {\n try {\n const stats = await stat(options.mappingFile);\n checks.push({\n name: \"mapping\",\n passed: stats.isFile(),\n message: stats.isFile()\n ? `Mapping file found (${formatSize(stats.size)})`\n : \"Mapping path is not a file\",\n });\n } catch {\n checks.push({\n name: \"mapping\",\n passed: false,\n message: `Mapping file not found: ${options.mappingFile}`,\n });\n }\n }\n\n // 3. Track validation\n if (options.track) {\n const isValid = STANDARD_TRACKS.has(options.track) || TRACK_PATTERN.test(options.track);\n checks.push({\n name: \"track\",\n passed: isValid,\n message: isValid\n ? `Track \"${options.track}\" is valid`\n : `Invalid track name \"${options.track}\". Use: internal, alpha, beta, production, or a custom track ID`,\n });\n }\n\n // 4. Release notes validation\n let resolvedNotes = options.notes;\n if (options.notesDir) {\n try {\n resolvedNotes = await readReleaseNotesFromDir(options.notesDir);\n checks.push({\n name: \"notes-dir\",\n passed: true,\n message: `Read release notes for ${resolvedNotes.length} language(s)`,\n });\n } catch (err) {\n checks.push({\n name: \"notes-dir\",\n passed: false,\n message: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n if (resolvedNotes && resolvedNotes.length > 0) {\n const notesResult = validateReleaseNotes(resolvedNotes);\n checks.push({\n name: \"notes\",\n passed: notesResult.valid,\n message: notesResult.valid\n ? `Release notes valid (${resolvedNotes.length} language(s))`\n : notesResult.errors.join(\"; \"),\n });\n for (const w of notesResult.warnings) resultWarnings.push(w);\n }\n\n return {\n valid: checks.every((c) => c.passed),\n checks,\n warnings: resultWarnings,\n };\n}\n\nfunction formatSize(bytes: number): string {\n if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n if (bytes >= 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${bytes} B`;\n}\n","import type { PlayApiClient } from \"@gpc-cli/api\";\nimport { uploadRelease } from \"./releases.js\";\nimport type { UploadResult, DryRunUploadResult } from \"./releases.js\";\nimport { validatePreSubmission } from \"./validate.js\";\nimport type { ValidateResult } from \"./validate.js\";\nimport { readReleaseNotesFromDir } from \"../utils/release-notes.js\";\n\nexport interface PublishOptions {\n track?: string;\n rolloutPercent?: number;\n notes?: string;\n notesDir?: string;\n releaseName?: string;\n mappingFile?: string;\n dryRun?: boolean;\n}\n\nexport interface PublishResult {\n validation: ValidateResult;\n upload?: UploadResult;\n}\n\nexport interface DryRunPublishResult {\n dryRun: true;\n validation: ValidateResult;\n upload: DryRunUploadResult;\n}\n\nexport async function publish(\n client: PlayApiClient,\n packageName: string,\n filePath: string,\n options: PublishOptions,\n): Promise<PublishResult | DryRunPublishResult> {\n // Resolve release notes\n let releaseNotes: { language: string; text: string }[] | undefined;\n if (options.notesDir) {\n releaseNotes = await readReleaseNotesFromDir(options.notesDir);\n } else if (options.notes) {\n releaseNotes = [{ language: \"en-US\", text: options.notes }];\n }\n\n // Validate\n const validation = await validatePreSubmission({\n filePath,\n mappingFile: options.mappingFile,\n track: options.track || \"internal\",\n notes: releaseNotes,\n });\n\n if (options.dryRun) {\n const upload = (await uploadRelease(client, packageName, filePath, {\n track: options.track || \"internal\",\n userFraction: options.rolloutPercent ? options.rolloutPercent / 100 : undefined,\n dryRun: true,\n })) as DryRunUploadResult;\n\n return { dryRun: true, validation, upload };\n }\n\n if (!validation.valid) {\n return { validation };\n }\n\n // Upload\n const upload = await uploadRelease(client, packageName, filePath, {\n track: options.track || \"internal\",\n userFraction: options.rolloutPercent ? options.rolloutPercent / 100 : undefined,\n releaseNotes,\n releaseName: options.releaseName,\n mappingFile: options.mappingFile,\n });\n\n return { validation, upload } as PublishResult;\n}\n","import type { PlayApiClient, Review, ReviewsListOptions, ReviewReplyResponse } from \"@gpc-cli/api\";\nimport { paginateAll } from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\nimport { analyzeReviews as analyzeReviewsSentiment } from \"../utils/sentiment.js\";\nimport type { ReviewAnalysis } from \"../utils/sentiment.js\";\n\nexport interface ReviewsFilterOptions {\n stars?: number;\n language?: string;\n since?: string;\n translationLanguage?: string;\n maxResults?: number;\n limit?: number;\n nextPage?: string;\n}\n\nexport interface ReviewExportOptions extends ReviewsFilterOptions {\n format?: \"json\" | \"csv\";\n}\n\nexport async function listReviews(\n client: PlayApiClient,\n packageName: string,\n options?: ReviewsFilterOptions,\n): Promise<Review[]> {\n const apiOptions: ReviewsListOptions = {};\n if (options?.translationLanguage) apiOptions.translationLanguage = options.translationLanguage;\n if (options?.maxResults) apiOptions.maxResults = options.maxResults;\n\n const response = await client.reviews.list(packageName, apiOptions);\n let reviews = response.reviews || [];\n\n // Client-side filters\n if (options?.stars !== undefined) {\n reviews = reviews.filter((r) => {\n const userComment = r.comments?.[0]?.userComment;\n return userComment && userComment.starRating === options.stars;\n });\n }\n\n if (options?.language) {\n reviews = reviews.filter((r) => {\n const userComment = r.comments?.[0]?.userComment;\n return userComment?.reviewerLanguage === options.language;\n });\n }\n\n if (options?.since) {\n const sinceTime = new Date(options.since).getTime() / 1000;\n reviews = reviews.filter((r) => {\n const userComment = r.comments?.[0]?.userComment;\n return userComment && Number(userComment.lastModified.seconds) >= sinceTime;\n });\n }\n\n return reviews;\n}\n\nexport async function getReview(\n client: PlayApiClient,\n packageName: string,\n reviewId: string,\n translationLanguage?: string,\n): Promise<Review> {\n return client.reviews.get(packageName, reviewId, translationLanguage);\n}\n\nconst MAX_REPLY_LENGTH = 350;\n\nexport async function replyToReview(\n client: PlayApiClient,\n packageName: string,\n reviewId: string,\n replyText: string,\n): Promise<ReviewReplyResponse> {\n if (replyText.length > MAX_REPLY_LENGTH) {\n throw new GpcError(\n `Reply text exceeds ${MAX_REPLY_LENGTH} characters (${replyText.length}). Google Play limits replies to ${MAX_REPLY_LENGTH} characters.`,\n \"REVIEW_REPLY_TOO_LONG\",\n 2,\n `Shorten your reply to ${MAX_REPLY_LENGTH} characters or fewer. Current length: ${replyText.length}.`,\n );\n }\n if (replyText.length === 0) {\n throw new GpcError(\n \"Reply text cannot be empty.\",\n \"REVIEW_REPLY_EMPTY\",\n 2,\n \"Provide a non-empty reply text with --text or -t.\",\n );\n }\n return client.reviews.reply(packageName, reviewId, replyText);\n}\n\nexport async function exportReviews(\n client: PlayApiClient,\n packageName: string,\n options?: ReviewExportOptions,\n): Promise<string> {\n const { items: allReviews } = await paginateAll<Review>(async (pageToken) => {\n const apiOptions: ReviewsListOptions = { token: pageToken };\n if (options?.translationLanguage) apiOptions.translationLanguage = options.translationLanguage;\n const response = await client.reviews.list(packageName, apiOptions);\n return {\n items: response.reviews || [],\n nextPageToken: response.tokenPagination?.nextPageToken,\n };\n });\n\n let filtered = allReviews;\n\n if (options?.stars !== undefined) {\n filtered = filtered.filter((r) => {\n const uc = r.comments?.[0]?.userComment;\n return uc && uc.starRating === options.stars;\n });\n }\n\n if (options?.language) {\n filtered = filtered.filter((r) => {\n const uc = r.comments?.[0]?.userComment;\n return uc?.reviewerLanguage === options.language;\n });\n }\n\n if (options?.since) {\n const sinceTime = new Date(options.since).getTime() / 1000;\n filtered = filtered.filter((r) => {\n const uc = r.comments?.[0]?.userComment;\n return uc && Number(uc.lastModified.seconds) >= sinceTime;\n });\n }\n\n if (options?.format === \"csv\") {\n return reviewsToCsv(filtered);\n }\n\n return JSON.stringify(filtered, null, 2);\n}\n\nfunction reviewsToCsv(reviews: Review[]): string {\n const header = \"reviewId,authorName,starRating,text,language,date,device,appVersionName\";\n const rows = reviews.map((r) => {\n const uc = r.comments?.[0]?.userComment;\n const fields = [\n r.reviewId,\n csvEscape(r.authorName),\n uc?.starRating ?? \"\",\n csvEscape(uc?.text ?? \"\"),\n uc?.reviewerLanguage ?? \"\",\n uc ? new Date(Number(uc.lastModified.seconds) * 1000).toISOString() : \"\",\n csvEscape(uc?.device ?? \"\"),\n csvEscape(uc?.appVersionName ?? \"\"),\n ];\n return fields.join(\",\");\n });\n return [header, ...rows].join(\"\\n\");\n}\n\nfunction csvEscape(value: string): string {\n if (value.includes(\",\") || value.includes('\"') || value.includes(\"\\n\")) {\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\n }\n return value;\n}\n\nexport { ReviewAnalysis };\n\n/** Fetch reviews and run local sentiment/topic/keyword analysis. */\nexport async function analyzeReviews(\n client: PlayApiClient,\n packageName: string,\n options?: ReviewsFilterOptions,\n): Promise<ReviewAnalysis> {\n const reviews = await listReviews(client, packageName, options);\n\n const items = reviews.map((r) => {\n const uc = r.comments?.[0]?.userComment;\n return {\n text: uc?.text ?? \"\",\n rating: uc?.starRating,\n };\n });\n\n return analyzeReviewsSentiment(items);\n}\n","/**\n * Local NLP sentiment analysis for reviews. No external API required.\n * Pure functions — no mocks needed in tests.\n */\n\nexport interface SentimentResult {\n score: number; // -1 to +1\n label: \"positive\" | \"negative\" | \"neutral\";\n magnitude: number; // 0 to 1 (confidence)\n}\n\nexport interface TopicCluster {\n topic: string;\n count: number;\n avgScore: number;\n}\n\nexport interface KeywordFrequency {\n word: string;\n count: number;\n}\n\nexport interface ReviewAnalysis {\n totalReviews: number;\n avgRating: number;\n sentiment: {\n positive: number;\n negative: number;\n neutral: number;\n avgScore: number;\n };\n topics: TopicCluster[];\n keywords: KeywordFrequency[];\n ratingDistribution: Record<number, number>;\n}\n\n// Simple lexicon-based sentiment analysis\nconst POSITIVE_WORDS = new Set([\n \"great\",\n \"excellent\",\n \"amazing\",\n \"awesome\",\n \"fantastic\",\n \"love\",\n \"good\",\n \"best\",\n \"perfect\",\n \"wonderful\",\n \"helpful\",\n \"easy\",\n \"fast\",\n \"smooth\",\n \"reliable\",\n \"clean\",\n \"beautiful\",\n \"intuitive\",\n \"works\",\n \"recommend\",\n \"useful\",\n \"thank\",\n \"thanks\",\n \"brilliant\",\n \"superb\",\n \"flawless\",\n \"outstanding\",\n \"delightful\",\n \"nice\",\n]);\n\nconst NEGATIVE_WORDS = new Set([\n \"bad\",\n \"terrible\",\n \"awful\",\n \"horrible\",\n \"worst\",\n \"hate\",\n \"broken\",\n \"crash\",\n \"crashes\",\n \"bug\",\n \"bugs\",\n \"slow\",\n \"laggy\",\n \"freeze\",\n \"freezes\",\n \"error\",\n \"errors\",\n \"fail\",\n \"fails\",\n \"useless\",\n \"disappointing\",\n \"disappointed\",\n \"frustrating\",\n \"frustration\",\n \"annoying\",\n \"problem\",\n \"problems\",\n \"issue\",\n \"issues\",\n \"fix\",\n \"please\",\n \"not working\",\n \"doesn't work\",\n \"stopped\",\n \"uninstall\",\n \"deleted\",\n \"waste\",\n \"rubbish\",\n \"garbage\",\n \"terrible\",\n]);\n\nconst STOP_WORDS = new Set([\n \"the\",\n \"a\",\n \"an\",\n \"and\",\n \"or\",\n \"but\",\n \"in\",\n \"on\",\n \"at\",\n \"to\",\n \"for\",\n \"of\",\n \"with\",\n \"is\",\n \"it\",\n \"this\",\n \"that\",\n \"was\",\n \"are\",\n \"be\",\n \"been\",\n \"have\",\n \"has\",\n \"had\",\n \"do\",\n \"does\",\n \"did\",\n \"will\",\n \"would\",\n \"could\",\n \"should\",\n \"may\",\n \"might\",\n \"i\",\n \"me\",\n \"my\",\n \"we\",\n \"you\",\n \"he\",\n \"she\",\n \"they\",\n \"them\",\n \"their\",\n \"its\",\n \"not\",\n \"no\",\n \"very\",\n \"so\",\n \"just\",\n \"really\",\n \"app\",\n \"application\",\n \"update\",\n]);\n\n/** Analyze sentiment of a single text. */\nexport function analyzeSentiment(text: string): SentimentResult {\n const lower = text.toLowerCase();\n const words = lower.split(/\\W+/).filter(Boolean);\n\n let posScore = 0;\n let negScore = 0;\n\n for (const word of words) {\n if (POSITIVE_WORDS.has(word)) posScore++;\n if (NEGATIVE_WORDS.has(word)) negScore++;\n }\n\n const total = posScore + negScore;\n if (total === 0) return { score: 0, label: \"neutral\", magnitude: 0 };\n\n const score = (posScore - negScore) / total;\n const magnitude = Math.min(1, total / 10);\n const label = score > 0.1 ? \"positive\" : score < -0.1 ? \"negative\" : \"neutral\";\n\n return { score, label, magnitude };\n}\n\n/** Cluster reviews into topics based on keyword co-occurrence. */\nexport function clusterTopics(texts: string[]): TopicCluster[] {\n const TOPIC_KEYWORDS: Record<string, string[]> = {\n performance: [\"slow\", \"lag\", \"laggy\", \"freeze\", \"fast\", \"speed\", \"quick\", \"smooth\"],\n crashes: [\"crash\", \"crashes\", \"crash\", \"crashing\", \"force close\", \"stops\", \"stopped\"],\n \"ui/ux\": [\"ui\", \"design\", \"interface\", \"layout\", \"button\", \"screen\", \"menu\", \"navigation\"],\n battery: [\"battery\", \"drain\", \"power\", \"charging\", \"drain\"],\n updates: [\"update\", \"updated\", \"version\", \"new version\", \"after update\"],\n notifications: [\"notification\", \"notifications\", \"alert\", \"alerts\", \"push\"],\n \"login/auth\": [\"login\", \"sign in\", \"logout\", \"password\", \"account\", \"auth\"],\n \"feature requests\": [\"please add\", \"would be nice\", \"missing\", \"need\", \"wish\", \"want\"],\n bugs: [\"bug\", \"bugs\", \"issue\", \"error\", \"problem\", \"glitch\", \"broken\"],\n pricing: [\"price\", \"pricing\", \"expensive\", \"cheap\", \"subscription\", \"pay\", \"cost\", \"free\"],\n };\n\n const clusterMap = new Map<string, { count: number; totalScore: number }>();\n\n for (const text of texts) {\n const lower = text.toLowerCase();\n const sentiment = analyzeSentiment(text);\n\n for (const [topic, keywords] of Object.entries(TOPIC_KEYWORDS)) {\n if (keywords.some((kw) => lower.includes(kw))) {\n const existing = clusterMap.get(topic) ?? { count: 0, totalScore: 0 };\n clusterMap.set(topic, {\n count: existing.count + 1,\n totalScore: existing.totalScore + sentiment.score,\n });\n }\n }\n }\n\n return Array.from(clusterMap.entries())\n .map(([topic, { count, totalScore }]) => ({\n topic,\n count,\n avgScore: count > 0 ? Math.round((totalScore / count) * 100) / 100 : 0,\n }))\n .filter((c) => c.count > 0)\n .sort((a, b) => b.count - a.count);\n}\n\n/** Count word frequency (excluding stop words). */\nexport function keywordFrequency(texts: string[], topN = 20): KeywordFrequency[] {\n const freq = new Map<string, number>();\n\n for (const text of texts) {\n const words = text\n .toLowerCase()\n .split(/\\W+/)\n .filter((w) => w.length > 3 && !STOP_WORDS.has(w));\n for (const word of words) {\n freq.set(word, (freq.get(word) ?? 0) + 1);\n }\n }\n\n return Array.from(freq.entries())\n .map(([word, count]) => ({ word, count }))\n .sort((a, b) => b.count - a.count)\n .slice(0, topN);\n}\n\n/** Full review analysis: sentiment, topics, keywords, rating distribution. */\nexport function analyzeReviews(reviews: { text: string; rating?: number }[]): ReviewAnalysis {\n if (reviews.length === 0) {\n return {\n totalReviews: 0,\n avgRating: 0,\n sentiment: { positive: 0, negative: 0, neutral: 0, avgScore: 0 },\n topics: [],\n keywords: [],\n ratingDistribution: {},\n };\n }\n\n const texts = reviews.map((r) => r.text);\n const sentiments = texts.map((t) => analyzeSentiment(t));\n\n const positive = sentiments.filter((s) => s.label === \"positive\").length;\n const negative = sentiments.filter((s) => s.label === \"negative\").length;\n const neutral = sentiments.filter((s) => s.label === \"neutral\").length;\n const avgScore = sentiments.reduce((sum, s) => sum + s.score, 0) / sentiments.length;\n\n const ratings = reviews.map((r) => r.rating).filter((r): r is number => r !== undefined);\n const avgRating = ratings.length > 0 ? ratings.reduce((a, b) => a + b, 0) / ratings.length : 0;\n\n const ratingDistribution: Record<number, number> = {};\n for (const r of ratings) {\n ratingDistribution[r] = (ratingDistribution[r] ?? 0) + 1;\n }\n\n return {\n totalReviews: reviews.length,\n avgRating: Math.round(avgRating * 100) / 100,\n sentiment: {\n positive,\n negative,\n neutral,\n avgScore: Math.round(avgScore * 100) / 100,\n },\n topics: clusterTopics(texts),\n keywords: keywordFrequency(texts),\n ratingDistribution,\n };\n}\n","import type {\n PlayApiClient,\n Subscription,\n BasePlanMigratePricesRequest,\n SubscriptionOffer,\n OffersListResponse,\n Money,\n} from \"@gpc-cli/api\";\nimport { paginateAll } from \"@gpc-cli/api\";\nimport { validatePackageName, validateSku } from \"../utils/validation.js\";\nimport { GpcError } from \"../errors.js\";\n\nexport interface ListSubscriptionsOptions {\n pageToken?: string;\n pageSize?: number;\n limit?: number;\n nextPage?: string;\n}\n\n// --- Sanitization: strip output-only fields, coerce types ---\n\nfunction coerceMoneyUnits(money: Money): Money {\n if (money.units !== undefined && typeof money.units !== \"string\") {\n return { ...money, units: String(money.units) };\n }\n return money;\n}\n\nfunction sanitizeSubscription(data: Subscription): Subscription {\n const { ...cleaned } = data;\n // Strip output-only fields from top level\n delete (cleaned as Record<string, unknown>)[\"state\"];\n delete (cleaned as Record<string, unknown>)[\"archived\"];\n\n if (cleaned.basePlans) {\n cleaned.basePlans = cleaned.basePlans.map((bp) => {\n const { state: _state, archived: _archived, ...cleanBp } = bp;\n void _state;\n void _archived;\n // Coerce Money.units to string in regional configs\n if (cleanBp.regionalConfigs) {\n cleanBp.regionalConfigs = cleanBp.regionalConfigs.map((rc) => ({\n ...rc,\n price: coerceMoneyUnits(rc.price),\n }));\n }\n return cleanBp;\n });\n }\n return cleaned;\n}\n\nfunction sanitizeOffer(data: SubscriptionOffer): SubscriptionOffer {\n const { state: _state2, ...cleaned } = data;\n void _state2;\n delete (cleaned as Record<string, unknown>)[\"archived\"];\n return cleaned as SubscriptionOffer;\n}\n\n// --- Client-side validation ---\n\nfunction parseDuration(iso: string): number {\n const match = iso.match(/^P(\\d+)D$/);\n return match?.[1] ? parseInt(match[1], 10) : 0;\n}\n\nconst PRORATION_MODE_PREFIX = \"SUBSCRIPTION_PRORATION_MODE_\";\nconst VALID_PRORATION_MODES = [\n \"SUBSCRIPTION_PRORATION_MODE_CHARGE_ON_NEXT_BILLING_DATE\",\n \"SUBSCRIPTION_PRORATION_MODE_CHARGE_FULL_PRICE_IMMEDIATELY\",\n];\n\nfunction autoFixProrationMode(data: Subscription): void {\n if (!data.basePlans) return;\n for (const bp of data.basePlans) {\n const mode = bp.autoRenewingBasePlanType?.prorationMode;\n if (mode && !mode.startsWith(PRORATION_MODE_PREFIX)) {\n if (bp.autoRenewingBasePlanType)\n bp.autoRenewingBasePlanType.prorationMode = `${PRORATION_MODE_PREFIX}${mode}`;\n }\n if (bp.autoRenewingBasePlanType?.prorationMode) {\n const fullMode = bp.autoRenewingBasePlanType.prorationMode;\n if (!VALID_PRORATION_MODES.includes(fullMode)) {\n throw new GpcError(\n `Invalid prorationMode: \"${fullMode}\"`,\n \"INVALID_SUBSCRIPTION_DATA\",\n 2,\n `Valid values: ${VALID_PRORATION_MODES.join(\", \")}`,\n );\n }\n }\n }\n}\n\nfunction validateSubscriptionData(data: Subscription): void {\n // Auto-fix prorationMode prefix\n autoFixProrationMode(data);\n\n // Validate listings\n if (data.listings) {\n for (const [lang, listing] of Object.entries(data.listings)) {\n if (listing.benefits && listing.benefits.length > 4) {\n throw new GpcError(\n `Listing \"${lang}\" has ${listing.benefits.length} benefits (max 4)`,\n \"INVALID_SUBSCRIPTION_DATA\",\n 2,\n \"Google Play allows a maximum of 4 benefits per subscription listing\",\n );\n }\n if (listing.description && listing.description.length > 80) {\n throw new GpcError(\n `Listing \"${lang}\" description is ${listing.description.length} chars (max 80)`,\n \"INVALID_SUBSCRIPTION_DATA\",\n 2,\n \"Google Play limits subscription descriptions to 80 characters\",\n );\n }\n }\n }\n\n // Validate base plan durations\n if (data.basePlans) {\n for (const bp of data.basePlans) {\n const autoType = bp.autoRenewingBasePlanType;\n if (autoType?.gracePeriodDuration && autoType?.accountHoldDuration) {\n const grace = parseDuration(autoType.gracePeriodDuration);\n const hold = parseDuration(autoType.accountHoldDuration);\n const sum = grace + hold;\n if (sum < 30 || sum > 60) {\n throw new GpcError(\n `Base plan \"${bp.basePlanId}\": gracePeriodDuration (${grace}d) + accountHoldDuration (${hold}d) = ${sum}d (must be 30-60)`,\n \"INVALID_SUBSCRIPTION_DATA\",\n 2,\n \"gracePeriodDuration + accountHoldDuration must sum to between P30D and P60D\",\n );\n }\n }\n }\n }\n}\n\nexport async function listSubscriptions(\n client: PlayApiClient,\n packageName: string,\n options?: ListSubscriptionsOptions,\n): Promise<{ subscriptions: Subscription[]; nextPageToken?: string }> {\n validatePackageName(packageName);\n if (options?.limit || options?.nextPage) {\n const result = await paginateAll<Subscription>(\n async (pageToken) => {\n const resp = await client.subscriptions.list(packageName, {\n pageToken,\n pageSize: options?.pageSize,\n });\n return { items: resp.subscriptions || [], nextPageToken: resp.nextPageToken };\n },\n { limit: options.limit, startPageToken: options.nextPage },\n );\n return { subscriptions: result.items, nextPageToken: result.nextPageToken };\n }\n return client.subscriptions.list(packageName, {\n pageToken: options?.pageToken,\n pageSize: options?.pageSize,\n });\n}\n\nexport async function getSubscription(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n): Promise<Subscription> {\n validatePackageName(packageName);\n validateSku(productId);\n return client.subscriptions.get(packageName, productId);\n}\n\nexport async function createSubscription(\n client: PlayApiClient,\n packageName: string,\n data: Subscription,\n): Promise<Subscription> {\n validatePackageName(packageName);\n validateSubscriptionData(data);\n const sanitized = sanitizeSubscription(data);\n return client.subscriptions.create(packageName, sanitized, data.productId);\n}\n\nconst SUBSCRIPTION_ID_FIELDS = new Set([\"productId\", \"packageName\"]);\n\nfunction deriveSubscriptionUpdateMask(data: Subscription): string {\n return Object.keys(data)\n .filter((k) => !SUBSCRIPTION_ID_FIELDS.has(k))\n .join(\",\");\n}\n\nexport async function updateSubscription(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n data: Subscription,\n updateMask?: string,\n): Promise<Subscription> {\n validatePackageName(packageName);\n validateSku(productId);\n validateSubscriptionData(data);\n const sanitized = sanitizeSubscription(data);\n const mask = updateMask || deriveSubscriptionUpdateMask(data);\n return client.subscriptions.update(packageName, productId, sanitized, mask);\n}\n\nexport async function deleteSubscription(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n): Promise<void> {\n validatePackageName(packageName);\n validateSku(productId);\n return client.subscriptions.delete(packageName, productId);\n}\n\nexport async function activateBasePlan(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n basePlanId: string,\n): Promise<Subscription> {\n validatePackageName(packageName);\n validateSku(productId);\n return client.subscriptions.activateBasePlan(packageName, productId, basePlanId);\n}\n\nexport async function deactivateBasePlan(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n basePlanId: string,\n): Promise<Subscription> {\n validatePackageName(packageName);\n validateSku(productId);\n return client.subscriptions.deactivateBasePlan(packageName, productId, basePlanId);\n}\n\nexport async function deleteBasePlan(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n basePlanId: string,\n): Promise<void> {\n validatePackageName(packageName);\n validateSku(productId);\n return client.subscriptions.deleteBasePlan(packageName, productId, basePlanId);\n}\n\nexport async function migratePrices(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n basePlanId: string,\n data: BasePlanMigratePricesRequest,\n): Promise<Subscription> {\n validatePackageName(packageName);\n validateSku(productId);\n return client.subscriptions.migratePrices(packageName, productId, basePlanId, data);\n}\n\nexport async function listOffers(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n basePlanId: string,\n): Promise<OffersListResponse> {\n validatePackageName(packageName);\n validateSku(productId);\n return client.subscriptions.listOffers(packageName, productId, basePlanId);\n}\n\nexport async function getOffer(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n): Promise<SubscriptionOffer> {\n validatePackageName(packageName);\n validateSku(productId);\n return client.subscriptions.getOffer(packageName, productId, basePlanId, offerId);\n}\n\nexport async function createOffer(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n basePlanId: string,\n data: SubscriptionOffer,\n): Promise<SubscriptionOffer> {\n validatePackageName(packageName);\n validateSku(productId);\n const sanitized = sanitizeOffer(data);\n return client.subscriptions.createOffer(\n packageName,\n productId,\n basePlanId,\n sanitized,\n data.offerId,\n );\n}\n\nconst OFFER_ID_FIELDS = new Set([\"productId\", \"basePlanId\", \"offerId\"]);\n\nfunction deriveOfferUpdateMask(data: SubscriptionOffer): string {\n return Object.keys(data)\n .filter((k) => !OFFER_ID_FIELDS.has(k))\n .join(\",\");\n}\n\nexport async function updateOffer(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n data: SubscriptionOffer,\n updateMask?: string,\n): Promise<SubscriptionOffer> {\n validatePackageName(packageName);\n validateSku(productId);\n const sanitized = sanitizeOffer(data);\n const mask = updateMask || deriveOfferUpdateMask(data);\n return client.subscriptions.updateOffer(\n packageName,\n productId,\n basePlanId,\n offerId,\n sanitized,\n mask,\n );\n}\n\nexport async function deleteOffer(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n): Promise<void> {\n validatePackageName(packageName);\n validateSku(productId);\n return client.subscriptions.deleteOffer(packageName, productId, basePlanId, offerId);\n}\n\nexport async function activateOffer(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n): Promise<SubscriptionOffer> {\n validatePackageName(packageName);\n validateSku(productId);\n return client.subscriptions.activateOffer(packageName, productId, basePlanId, offerId);\n}\n\nexport interface SubscriptionDiff {\n field: string;\n local: string;\n remote: string;\n}\n\nexport async function diffSubscription(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n localData: Subscription,\n): Promise<SubscriptionDiff[]> {\n validatePackageName(packageName);\n validateSku(productId);\n const remote = await client.subscriptions.get(packageName, productId);\n const diffs: SubscriptionDiff[] = [];\n const fieldsToCompare = [\"listings\", \"basePlans\", \"taxAndComplianceSettings\"];\n\n for (const field of fieldsToCompare) {\n const localVal = JSON.stringify(\n (localData as unknown as Record<string, unknown>)[field] ?? null,\n );\n const remoteVal = JSON.stringify((remote as unknown as Record<string, unknown>)[field] ?? null);\n if (localVal !== remoteVal) {\n diffs.push({ field, local: localVal, remote: remoteVal });\n }\n }\n return diffs;\n}\n\nexport async function deactivateOffer(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n): Promise<SubscriptionOffer> {\n validatePackageName(packageName);\n validateSku(productId);\n return client.subscriptions.deactivateOffer(packageName, productId, basePlanId, offerId);\n}\n\nexport interface SubscriptionAnalytics {\n totalSubscriptions: number;\n activeCount: number;\n activeBasePlans: number;\n trialBasePlans: number;\n pausedBasePlans: number;\n canceledBasePlans: number;\n offerCount: number;\n byProductId: Array<{\n productId: string;\n state: string;\n basePlanCount: number;\n offerCount: number;\n }>;\n}\n\n/** Aggregate subscription catalog analytics from the Play API. */\nexport async function getSubscriptionAnalytics(\n client: PlayApiClient,\n packageName: string,\n): Promise<SubscriptionAnalytics> {\n validatePackageName(packageName);\n\n const { items: subs } = await paginateAll<Subscription>(async (pageToken) => {\n const response = await client.subscriptions.list(packageName, {\n pageToken,\n pageSize: 100,\n });\n return {\n items: response.subscriptions || [],\n nextPageToken: response.nextPageToken,\n };\n });\n\n let activeCount = 0;\n let activeBasePlans = 0;\n let trialBasePlans = 0;\n let pausedBasePlans = 0;\n let canceledBasePlans = 0;\n let totalOffers = 0;\n\n const byProductId: SubscriptionAnalytics[\"byProductId\"] = [];\n\n for (const sub of subs) {\n const state = (sub as unknown as Record<string, unknown>)[\"state\"] as string | undefined;\n if (state === \"ACTIVE\") activeCount++;\n\n const basePlans = sub.basePlans ?? [];\n let subOfferCount = 0;\n\n for (const bp of basePlans) {\n const bpState = (bp as unknown as Record<string, unknown>)[\"state\"] as string | undefined;\n if (bpState === \"ACTIVE\") activeBasePlans++;\n else if (bpState === \"DRAFT\") trialBasePlans++;\n else if (bpState === \"INACTIVE\") pausedBasePlans++;\n else if (bpState === \"PREPUBLISHED\") canceledBasePlans++;\n }\n\n // Count offers across all base plans\n for (const bp of basePlans) {\n try {\n const offersResp = await client.subscriptions.listOffers(\n packageName,\n sub.productId,\n bp.basePlanId,\n );\n const offers = offersResp.subscriptionOffers ?? [];\n subOfferCount += offers.length;\n totalOffers += offers.length;\n } catch {\n // offers may not be accessible for all base plans\n }\n }\n\n byProductId.push({\n productId: sub.productId,\n state: ((sub as unknown as Record<string, unknown>)[\"state\"] as string) ?? \"UNKNOWN\",\n basePlanCount: basePlans.length,\n offerCount: subOfferCount,\n });\n }\n\n return {\n totalSubscriptions: subs.length,\n activeCount,\n activeBasePlans,\n trialBasePlans,\n pausedBasePlans,\n canceledBasePlans,\n offerCount: totalOffers,\n byProductId,\n };\n}\n","import type {\n ReportingApiClient,\n VitalsMetricSet,\n MetricSetQuery,\n MetricSetResponse,\n MetricRow,\n AnomalyDetectionResponse,\n ErrorIssuesResponse,\n ReportingDimension,\n ReportingAggregation,\n} from \"@gpc-cli/api\";\n\nexport interface VitalsQueryOptions {\n dimension?: ReportingDimension;\n days?: number;\n aggregation?: ReportingAggregation;\n}\n\nexport interface VitalsOverview {\n crashRate?: MetricRow[];\n anrRate?: MetricRow[];\n slowStartRate?: MetricRow[];\n slowRenderingRate?: MetricRow[];\n excessiveWakeupRate?: MetricRow[];\n stuckWakelockRate?: MetricRow[];\n}\n\nexport interface ThresholdResult {\n breached: boolean;\n value: number | undefined;\n threshold: number;\n}\n\nconst METRIC_SET_METRICS: Record<VitalsMetricSet, string[]> = {\n crashRateMetricSet: [\"crashRate\", \"userPerceivedCrashRate\", \"distinctUsers\"],\n anrRateMetricSet: [\"anrRate\", \"userPerceivedAnrRate\", \"distinctUsers\"],\n slowStartRateMetricSet: [\"slowStartRate\", \"distinctUsers\"],\n slowRenderingRateMetricSet: [\"slowRenderingRate\", \"distinctUsers\"],\n excessiveWakeupRateMetricSet: [\"excessiveWakeupRate\", \"distinctUsers\"],\n stuckBackgroundWakelockRateMetricSet: [\n \"stuckBgWakelockRate\",\n \"stuckBgWakelockRate7dUserWeighted\",\n \"stuckBgWakelockRate28dUserWeighted\",\n \"distinctUsers\",\n ],\n errorCountMetricSet: [\"errorReportCount\", \"distinctUsers\"],\n};\n\nfunction buildQuery(metricSet: VitalsMetricSet, options?: VitalsQueryOptions): MetricSetQuery {\n const metrics = METRIC_SET_METRICS[metricSet] ?? [\"errorReportCount\", \"distinctUsers\"];\n\n const days = options?.days ?? 30;\n const DAY_MS = 24 * 60 * 60 * 1000;\n const end = new Date(Date.now() - DAY_MS); // API data lags ~1 day; cap to yesterday\n const start = new Date(Date.now() - DAY_MS - days * DAY_MS);\n\n const query: MetricSetQuery = {\n metrics,\n timelineSpec: {\n aggregationPeriod: options?.aggregation ?? \"DAILY\",\n startTime: {\n year: start.getUTCFullYear(),\n month: start.getUTCMonth() + 1,\n day: start.getUTCDate(),\n },\n endTime: {\n year: end.getUTCFullYear(),\n month: end.getUTCMonth() + 1,\n day: end.getUTCDate(),\n },\n },\n };\n\n if (options?.dimension) {\n query.dimensions = [options.dimension];\n }\n\n return query;\n}\n\nasync function queryMetric(\n reporting: ReportingApiClient,\n packageName: string,\n metricSet: VitalsMetricSet,\n options?: VitalsQueryOptions,\n): Promise<MetricSetResponse> {\n const query = buildQuery(metricSet, options);\n return reporting.queryMetricSet(packageName, metricSet, query);\n}\n\nexport async function getVitalsOverview(\n reporting: ReportingApiClient,\n packageName: string,\n): Promise<VitalsOverview> {\n const metricSets: [VitalsMetricSet, keyof VitalsOverview][] = [\n [\"crashRateMetricSet\", \"crashRate\"],\n [\"anrRateMetricSet\", \"anrRate\"],\n [\"slowStartRateMetricSet\", \"slowStartRate\"],\n [\"slowRenderingRateMetricSet\", \"slowRenderingRate\"],\n [\"excessiveWakeupRateMetricSet\", \"excessiveWakeupRate\"],\n [\"stuckBackgroundWakelockRateMetricSet\", \"stuckWakelockRate\"],\n ];\n\n const results = await Promise.allSettled(\n metricSets.map(([metric]) => reporting.queryMetricSet(packageName, metric, buildQuery(metric))),\n );\n\n const overview: VitalsOverview = {};\n for (let i = 0; i < metricSets.length; i++) {\n const entry = metricSets[i];\n if (!entry) continue;\n const key = entry[1];\n const result = results[i];\n if (!result) continue;\n if (result.status === \"fulfilled\") {\n overview[key] = result.value.rows || [];\n }\n }\n\n return overview;\n}\n\nexport async function getVitalsCrashes(\n reporting: ReportingApiClient,\n packageName: string,\n options?: VitalsQueryOptions,\n): Promise<MetricSetResponse> {\n return queryMetric(reporting, packageName, \"crashRateMetricSet\", options);\n}\n\nexport async function getVitalsAnr(\n reporting: ReportingApiClient,\n packageName: string,\n options?: VitalsQueryOptions,\n): Promise<MetricSetResponse> {\n return queryMetric(reporting, packageName, \"anrRateMetricSet\", options);\n}\n\nexport async function getVitalsStartup(\n reporting: ReportingApiClient,\n packageName: string,\n options?: VitalsQueryOptions,\n): Promise<MetricSetResponse> {\n // API requires startType as a dimension for slowStartRateMetricSet;\n // auto-include it if no dimension is explicitly specified\n const opts = options?.dimension\n ? options\n : { ...options, dimension: \"startType\" as ReportingDimension };\n return queryMetric(reporting, packageName, \"slowStartRateMetricSet\", opts);\n}\n\nexport async function getVitalsRendering(\n reporting: ReportingApiClient,\n packageName: string,\n options?: VitalsQueryOptions,\n): Promise<MetricSetResponse> {\n return queryMetric(reporting, packageName, \"slowRenderingRateMetricSet\", options);\n}\n\nexport async function getVitalsBattery(\n reporting: ReportingApiClient,\n packageName: string,\n options?: VitalsQueryOptions,\n): Promise<MetricSetResponse> {\n return queryMetric(reporting, packageName, \"excessiveWakeupRateMetricSet\", options);\n}\n\nexport async function getVitalsMemory(\n reporting: ReportingApiClient,\n packageName: string,\n options?: VitalsQueryOptions,\n): Promise<MetricSetResponse> {\n return queryMetric(reporting, packageName, \"stuckBackgroundWakelockRateMetricSet\", options);\n}\n\n/** LMK-specific query: enforces DAILY aggregation as required by the API. */\nexport async function getVitalsLmk(\n reporting: ReportingApiClient,\n packageName: string,\n options?: VitalsQueryOptions,\n): Promise<MetricSetResponse> {\n return queryMetric(reporting, packageName, \"stuckBackgroundWakelockRateMetricSet\", {\n ...options,\n aggregation: \"DAILY\",\n });\n}\n\nexport async function getVitalsAnomalies(\n reporting: ReportingApiClient,\n packageName: string,\n): Promise<AnomalyDetectionResponse> {\n return reporting.getAnomalies(packageName);\n}\n\nexport async function searchVitalsErrors(\n reporting: ReportingApiClient,\n packageName: string,\n options?: { filter?: string; maxResults?: number },\n): Promise<ErrorIssuesResponse> {\n return reporting.searchErrorIssues(packageName, options?.filter, options?.maxResults);\n}\n\nexport interface VitalsTrendComparison {\n metric: string;\n current: number | undefined;\n previous: number | undefined;\n changePercent: number | undefined;\n direction: \"improved\" | \"degraded\" | \"unchanged\" | \"unknown\";\n}\n\nexport async function compareVitalsTrend(\n reporting: ReportingApiClient,\n packageName: string,\n metricSet: VitalsMetricSet,\n days: number = 7,\n): Promise<VitalsTrendComparison> {\n const DAY_MS = 24 * 60 * 60 * 1000;\n const nowMs = Date.now();\n\n // Cap to 2 days ago — API data typically lags 1-2 days; using 2 ensures\n // the endTime is always within the available data window.\n const baseMs = nowMs - 2 * DAY_MS;\n\n // Current period: [base - days, base]\n const currentEnd = new Date(baseMs);\n const currentStart = new Date(baseMs - days * DAY_MS);\n\n // Previous period: [base - 2*days - 1, base - days - 1] (1-day gap)\n const previousEnd = new Date(baseMs - days * DAY_MS - DAY_MS);\n const previousStart = new Date(baseMs - days * DAY_MS - DAY_MS - days * DAY_MS);\n\n const metrics = METRIC_SET_METRICS[metricSet] ?? [\"errorReportCount\", \"distinctUsers\"];\n\n // Use UTC accessors to avoid timezone-dependent off-by-one on date boundaries\n const toApiDate = (d: Date) => ({\n year: d.getUTCFullYear(),\n month: d.getUTCMonth() + 1,\n day: d.getUTCDate(),\n });\n\n const makeQuery = (start: Date, end: Date): MetricSetQuery => ({\n metrics,\n timelineSpec: {\n aggregationPeriod: \"DAILY\",\n startTime: toApiDate(start),\n endTime: toApiDate(end),\n },\n });\n\n const [currentResult, previousResult] = await Promise.all([\n reporting.queryMetricSet(packageName, metricSet, makeQuery(currentStart, currentEnd)),\n reporting.queryMetricSet(packageName, metricSet, makeQuery(previousStart, previousEnd)),\n ]);\n\n const extractAvg = (rows: MetricRow[] | undefined): number | undefined => {\n if (!rows || rows.length === 0) return undefined;\n const values = rows\n .map((r) => {\n const keys = Object.keys(r.metrics);\n const first = keys[0];\n return first ? Number(r.metrics[first]?.decimalValue?.value) : NaN;\n })\n .filter((v) => !isNaN(v));\n if (values.length === 0) return undefined;\n return values.reduce((a, b) => a + b, 0) / values.length;\n };\n\n const current = extractAvg(currentResult.rows);\n const previous = extractAvg(previousResult.rows);\n\n let changePercent: number | undefined;\n let direction: VitalsTrendComparison[\"direction\"] = \"unknown\";\n\n if (current !== undefined && previous !== undefined && previous !== 0) {\n changePercent = ((current - previous) / previous) * 100;\n if (Math.abs(changePercent) < 1) {\n direction = \"unchanged\";\n } else if (changePercent < 0) {\n direction = \"improved\"; // lower error rate = better\n } else {\n direction = \"degraded\";\n }\n }\n\n return {\n metric: metricSet,\n current,\n previous,\n changePercent: changePercent !== undefined ? Math.round(changePercent * 10) / 10 : undefined,\n direction,\n };\n}\n\nexport function checkThreshold(value: number | undefined, threshold: number): ThresholdResult {\n return {\n breached: value !== undefined && value > threshold,\n value,\n threshold,\n };\n}\n\nexport interface VersionVitalsRow {\n versionCode: string;\n crashRate?: number;\n anrRate?: number;\n slowStartRate?: number;\n slowRenderingRate?: number;\n}\n\nexport interface VersionVitalsComparison {\n v1: VersionVitalsRow;\n v2: VersionVitalsRow;\n regressions: string[];\n}\n\n/** Compare vitals side-by-side for two version codes. */\nexport async function compareVersionVitals(\n reporting: ReportingApiClient,\n packageName: string,\n v1: string,\n v2: string,\n options?: { days?: number },\n): Promise<VersionVitalsComparison> {\n const days = options?.days ?? 30;\n const metricSets: [VitalsMetricSet, keyof Omit<VersionVitalsRow, \"versionCode\">][] = [\n [\"crashRateMetricSet\", \"crashRate\"],\n [\"anrRateMetricSet\", \"anrRate\"],\n [\"slowStartRateMetricSet\", \"slowStartRate\"],\n [\"slowRenderingRateMetricSet\", \"slowRenderingRate\"],\n ];\n\n const results = await Promise.allSettled(\n metricSets.map(([ms]) =>\n queryMetric(reporting, packageName, ms, { dimension: \"versionCode\", days }),\n ),\n );\n\n const row1: VersionVitalsRow = { versionCode: v1 };\n const row2: VersionVitalsRow = { versionCode: v2 };\n\n for (let i = 0; i < metricSets.length; i++) {\n const entry = metricSets[i];\n const result = results[i];\n if (!entry || !result || result.status !== \"fulfilled\") continue;\n const key = entry[1];\n const rows = result.value.rows ?? [];\n\n const extractAvgForVersion = (vc: string): number | undefined => {\n const matching = rows.filter((r) => {\n const dims = r.dimensions as Record<string, unknown>[] | undefined;\n return dims?.some((d) => (d as Record<string, unknown>)[\"stringValue\"] === vc) ?? false;\n });\n if (matching.length === 0) return undefined;\n const values = matching\n .map((r) => {\n const firstKey = Object.keys(r.metrics)[0];\n return firstKey ? Number(r.metrics[firstKey]?.decimalValue?.value) : NaN;\n })\n .filter((v) => !isNaN(v));\n if (values.length === 0) return undefined;\n return values.reduce((a, b) => a + b, 0) / values.length;\n };\n\n (row1 as unknown as Record<string, unknown>)[key] = extractAvgForVersion(v1);\n (row2 as unknown as Record<string, unknown>)[key] = extractAvgForVersion(v2);\n }\n\n const regressions: string[] = [];\n for (const [, key] of metricSets) {\n const val1 = (row1 as unknown as Record<string, unknown>)[key] as number | undefined;\n const val2 = (row2 as unknown as Record<string, unknown>)[key] as number | undefined;\n if (val1 !== undefined && val2 !== undefined && val2 > val1 * 1.05) {\n regressions.push(key as string);\n }\n }\n\n return { v1: row1, v2: row2, regressions };\n}\n\nexport interface WatchVitalsOptions {\n /** Polling interval in milliseconds. Defaults to 5 minutes. */\n intervalMs?: number;\n /** Threshold value; breach triggers halt. */\n threshold: number;\n /** Metric set to monitor. Defaults to crashRateMetricSet. */\n metricSet?: VitalsMetricSet;\n /** Called when threshold is breached. Implement halt logic here. */\n onHalt?: (value: number) => Promise<void>;\n /** Called on each poll result (value may be undefined if no data). */\n onPoll?: (value: number | undefined, breached: boolean) => void;\n}\n\n/**\n * Poll vitals on an interval; invoke onHalt if threshold is breached.\n * Returns a stop function — call it to cancel the watch loop.\n */\nexport function watchVitalsWithAutoHalt(\n reporting: ReportingApiClient,\n packageName: string,\n options: WatchVitalsOptions,\n): () => void {\n const {\n intervalMs = 5 * 60 * 1000,\n threshold,\n metricSet = \"crashRateMetricSet\",\n onHalt,\n onPoll,\n } = options;\n\n let stopped = false;\n let haltTriggered = false;\n\n const poll = async () => {\n if (stopped) return;\n try {\n const result = await queryMetric(reporting, packageName, metricSet, { days: 1 });\n const latestRow = result.rows?.[result.rows.length - 1];\n const firstMetric = latestRow?.metrics ? Object.keys(latestRow.metrics)[0] : undefined;\n const value = firstMetric\n ? Number(latestRow?.metrics[firstMetric]?.decimalValue?.value)\n : undefined;\n\n const breached = value !== undefined && value > threshold;\n onPoll?.(value, breached);\n\n if (breached && !haltTriggered && onHalt) {\n haltTriggered = true;\n await onHalt(value as number);\n }\n } catch {\n // swallow errors in background polling\n }\n\n if (!stopped) {\n timerId = setTimeout(poll, intervalMs);\n }\n };\n\n let timerId = setTimeout(poll, 0);\n\n return () => {\n stopped = true;\n clearTimeout(timerId);\n };\n}\n","import { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { PlayApiClient, InAppProduct, InAppProductsBatchUpdateRequest } from \"@gpc-cli/api\";\nimport { paginateAll } from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\n\nexport interface ListIapOptions {\n token?: string;\n maxResults?: number;\n limit?: number;\n nextPage?: string;\n}\n\nexport async function listInAppProducts(\n client: PlayApiClient,\n packageName: string,\n options?: ListIapOptions,\n): Promise<{ inappproduct: InAppProduct[]; nextPageToken?: string }> {\n if (options?.limit || options?.nextPage) {\n const result = await paginateAll<InAppProduct>(\n async (pageToken) => {\n const resp = await client.inappproducts.list(packageName, {\n token: pageToken,\n maxResults: options?.maxResults,\n });\n return {\n items: resp.inappproduct || [],\n nextPageToken: resp.tokenPagination?.nextPageToken,\n };\n },\n { limit: options.limit, startPageToken: options.nextPage },\n );\n return { inappproduct: result.items, nextPageToken: result.nextPageToken };\n }\n return client.inappproducts.list(packageName, {\n token: options?.token,\n maxResults: options?.maxResults,\n });\n}\n\nexport async function getInAppProduct(\n client: PlayApiClient,\n packageName: string,\n sku: string,\n): Promise<InAppProduct> {\n return client.inappproducts.get(packageName, sku);\n}\n\nexport async function createInAppProduct(\n client: PlayApiClient,\n packageName: string,\n data: InAppProduct,\n): Promise<InAppProduct> {\n return client.inappproducts.create(packageName, data);\n}\n\nexport async function updateInAppProduct(\n client: PlayApiClient,\n packageName: string,\n sku: string,\n data: InAppProduct,\n): Promise<InAppProduct> {\n return client.inappproducts.update(packageName, sku, data);\n}\n\nexport async function deleteInAppProduct(\n client: PlayApiClient,\n packageName: string,\n sku: string,\n): Promise<void> {\n return client.inappproducts.delete(packageName, sku);\n}\n\nexport interface SyncResult {\n created: number;\n updated: number;\n unchanged: number;\n skus: string[];\n}\n\nexport async function syncInAppProducts(\n client: PlayApiClient,\n packageName: string,\n dir: string,\n options?: { dryRun?: boolean },\n): Promise<SyncResult> {\n const localProducts = await readProductsFromDir(dir);\n\n if (localProducts.length === 0) {\n return { created: 0, updated: 0, unchanged: 0, skus: [] };\n }\n\n const response = await client.inappproducts.list(packageName);\n const remoteSkus = new Set((response.inappproduct || []).map((p) => p.sku));\n\n const toUpdate = localProducts.filter((p) => remoteSkus.has(p.sku));\n const toCreate = localProducts.filter((p) => !remoteSkus.has(p.sku));\n const skus = localProducts.map((p) => p.sku);\n\n if (options?.dryRun) {\n return { created: toCreate.length, updated: toUpdate.length, unchanged: 0, skus };\n }\n\n // Attempt batch update for products that need updating (multiple items)\n if (toUpdate.length > 1) {\n try {\n await batchUpdateProducts(client, packageName, toUpdate);\n } catch {\n // Fallback to serial updates\n for (const product of toUpdate) {\n await client.inappproducts.update(packageName, product.sku, product);\n }\n }\n } else {\n for (const product of toUpdate) {\n await client.inappproducts.update(packageName, product.sku, product);\n }\n }\n\n for (const product of toCreate) {\n await client.inappproducts.create(packageName, product);\n }\n\n return { created: toCreate.length, updated: toUpdate.length, unchanged: 0, skus };\n}\n\nconst BATCH_CHUNK_SIZE = 100;\n\nasync function batchUpdateProducts(\n client: PlayApiClient,\n packageName: string,\n products: InAppProduct[],\n): Promise<InAppProduct[]> {\n const results: InAppProduct[] = [];\n for (let i = 0; i < products.length; i += BATCH_CHUNK_SIZE) {\n const chunk = products.slice(i, i + BATCH_CHUNK_SIZE);\n const request: InAppProductsBatchUpdateRequest = {\n requests: chunk.map((p) => ({\n inappproduct: p,\n packageName,\n sku: p.sku,\n })),\n };\n const response = await client.inappproducts.batchUpdate(packageName, request);\n results.push(...(response.inappproducts || []));\n }\n return results;\n}\n\nasync function readProductsFromDir(dir: string): Promise<InAppProduct[]> {\n const files = await readdir(dir);\n const jsonFiles = files.filter((f) => f.endsWith(\".json\"));\n const localProducts: InAppProduct[] = [];\n for (const file of jsonFiles) {\n const content = await readFile(join(dir, file), \"utf-8\");\n try {\n localProducts.push(JSON.parse(content) as InAppProduct);\n } catch {\n throw new GpcError(\n `Failed to parse ${file}: invalid JSON`,\n \"IAP_INVALID_JSON\",\n 1,\n `Check that \"${file}\" contains valid JSON. You can validate it with: cat \"${file}\" | jq .`,\n );\n }\n }\n return localProducts;\n}\n\nexport interface BatchSyncResult extends SyncResult {\n batchUsed: boolean;\n batchErrors: number;\n}\n\nexport async function batchSyncInAppProducts(\n client: PlayApiClient,\n packageName: string,\n dir: string,\n options?: { dryRun?: boolean },\n): Promise<BatchSyncResult> {\n const localProducts = await readProductsFromDir(dir);\n\n if (localProducts.length === 0) {\n return { created: 0, updated: 0, unchanged: 0, skus: [], batchUsed: false, batchErrors: 0 };\n }\n\n const response = await client.inappproducts.list(packageName);\n const remoteSkus = new Set((response.inappproduct || []).map((p) => p.sku));\n\n const toUpdate = localProducts.filter((p) => remoteSkus.has(p.sku));\n const toCreate = localProducts.filter((p) => !remoteSkus.has(p.sku));\n const skus = localProducts.map((p) => p.sku);\n\n if (options?.dryRun) {\n return {\n created: toCreate.length,\n updated: toUpdate.length,\n unchanged: 0,\n skus,\n batchUsed: toUpdate.length > 1,\n batchErrors: 0,\n };\n }\n\n let batchUsed = false;\n let batchErrors = 0;\n\n if (toUpdate.length > 1) {\n batchUsed = true;\n try {\n await batchUpdateProducts(client, packageName, toUpdate);\n } catch {\n batchErrors++;\n // Fallback to serial updates\n for (const product of toUpdate) {\n await client.inappproducts.update(packageName, product.sku, product);\n }\n }\n } else {\n for (const product of toUpdate) {\n await client.inappproducts.update(packageName, product.sku, product);\n }\n }\n\n for (const product of toCreate) {\n await client.inappproducts.create(packageName, product);\n }\n\n return {\n created: toCreate.length,\n updated: toUpdate.length,\n unchanged: 0,\n skus,\n batchUsed,\n batchErrors,\n };\n}\n","import type {\n PlayApiClient,\n ProductPurchase,\n ProductPurchaseV2,\n SubscriptionPurchaseV2,\n SubscriptionDeferResponse,\n SubscriptionsV2DeferResponse,\n Order,\n} from \"@gpc-cli/api\";\nimport { validatePackageName } from \"../utils/validation.js\";\nimport { GpcError } from \"../errors.js\";\n\nexport async function getProductPurchase(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n token: string,\n): Promise<ProductPurchase> {\n validatePackageName(packageName);\n return client.purchases.getProduct(packageName, productId, token);\n}\n\nexport async function acknowledgeProductPurchase(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n token: string,\n payload?: string,\n): Promise<void> {\n validatePackageName(packageName);\n const body = payload ? { developerPayload: payload } : undefined;\n return client.purchases.acknowledgeProduct(packageName, productId, token, body);\n}\n\nexport async function consumeProductPurchase(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n token: string,\n): Promise<void> {\n validatePackageName(packageName);\n return client.purchases.consumeProduct(packageName, productId, token);\n}\n\nexport async function getSubscriptionPurchase(\n client: PlayApiClient,\n packageName: string,\n token: string,\n): Promise<SubscriptionPurchaseV2> {\n validatePackageName(packageName);\n return client.purchases.getSubscriptionV2(packageName, token);\n}\n\nexport async function cancelSubscriptionPurchase(\n client: PlayApiClient,\n packageName: string,\n subscriptionId: string,\n token: string,\n): Promise<void> {\n validatePackageName(packageName);\n return client.purchases.cancelSubscription(packageName, subscriptionId, token);\n}\n\nexport async function deferSubscriptionPurchase(\n client: PlayApiClient,\n packageName: string,\n subscriptionId: string,\n token: string,\n desiredExpiry: string,\n): Promise<SubscriptionDeferResponse> {\n validatePackageName(packageName);\n const sub = await client.purchases.getSubscriptionV1(packageName, subscriptionId, token);\n return client.purchases.deferSubscription(packageName, subscriptionId, token, {\n deferralInfo: {\n expectedExpiryTimeMillis: sub.expiryTimeMillis,\n desiredExpiryTimeMillis: String(new Date(desiredExpiry).getTime()),\n },\n });\n}\n\nexport async function revokeSubscriptionPurchase(\n client: PlayApiClient,\n packageName: string,\n token: string,\n): Promise<void> {\n validatePackageName(packageName);\n return client.purchases.revokeSubscriptionV2(packageName, token);\n}\n\nexport async function refundSubscriptionV2(\n client: PlayApiClient,\n packageName: string,\n token: string,\n): Promise<void> {\n validatePackageName(packageName);\n return client.purchases.refundSubscriptionV2(packageName, token);\n}\n\nimport type { VoidedPurchase } from \"@gpc-cli/api\";\nimport { paginateAll } from \"@gpc-cli/api\";\n\nexport interface ListVoidedOptions {\n startTime?: string;\n endTime?: string;\n maxResults?: number;\n limit?: number;\n nextPage?: string;\n}\n\nexport async function listVoidedPurchases(\n client: PlayApiClient,\n packageName: string,\n options?: ListVoidedOptions,\n): Promise<{ voidedPurchases: VoidedPurchase[]; nextPageToken?: string }> {\n validatePackageName(packageName);\n if (options?.limit || options?.nextPage) {\n const result = await paginateAll<VoidedPurchase>(\n async (pageToken) => {\n const resp = await client.purchases.listVoided(packageName, {\n startTime: options?.startTime,\n endTime: options?.endTime,\n maxResults: options?.maxResults,\n token: pageToken,\n });\n return {\n items: resp.voidedPurchases || [],\n nextPageToken: resp.tokenPagination?.nextPageToken,\n };\n },\n { limit: options.limit, startPageToken: options.nextPage },\n );\n return { voidedPurchases: result.items, nextPageToken: result.nextPageToken };\n }\n return client.purchases.listVoided(packageName, options);\n}\n\nexport async function refundOrder(\n client: PlayApiClient,\n packageName: string,\n orderId: string,\n options?: { fullRefund?: boolean; proratedRefund?: boolean },\n): Promise<void> {\n validatePackageName(packageName);\n return client.orders.refund(packageName, orderId, options);\n}\n\n// --- Orders API (May 2025) ---\n\nexport async function getOrderDetails(\n client: PlayApiClient,\n packageName: string,\n orderId: string,\n): Promise<Order> {\n validatePackageName(packageName);\n return client.orders.get(packageName, orderId);\n}\n\nexport async function batchGetOrders(\n client: PlayApiClient,\n packageName: string,\n orderIds: string[],\n): Promise<Order[]> {\n validatePackageName(packageName);\n if (orderIds.length === 0) {\n throw new GpcError(\"No order IDs provided\", \"ORDERS_BATCH_EMPTY\", 2, \"Pass at least one order ID with --ids\");\n }\n if (orderIds.length > 1000) {\n throw new GpcError(`Too many order IDs (${orderIds.length}). Maximum is 1000.`, \"ORDERS_BATCH_LIMIT\", 2, \"Split into multiple requests of 1000 or fewer\");\n }\n return client.orders.batchGet(packageName, orderIds);\n}\n\n// --- ProductPurchaseV2 (Jun 2025) ---\n\nexport async function getProductPurchaseV2(\n client: PlayApiClient,\n packageName: string,\n token: string,\n): Promise<ProductPurchaseV2> {\n validatePackageName(packageName);\n return client.purchases.getProductV2(packageName, token);\n}\n\n// --- SubscriptionsV2 cancel/defer (Sep 2025 / Jan 2026) ---\n\nexport async function cancelSubscriptionV2(\n client: PlayApiClient,\n packageName: string,\n token: string,\n cancellationType?: string,\n): Promise<void> {\n validatePackageName(packageName);\n const body = cancellationType ? { cancellationType } : undefined;\n return client.purchases.cancelSubscriptionV2(packageName, token, body);\n}\n\nexport async function deferSubscriptionV2(\n client: PlayApiClient,\n packageName: string,\n token: string,\n desiredExpiryTime: string,\n): Promise<SubscriptionsV2DeferResponse> {\n validatePackageName(packageName);\n return client.purchases.deferSubscriptionV2(packageName, token, {\n deferralInfo: { desiredExpiryTime },\n });\n}\n","import type { PlayApiClient, ConvertRegionPricesResponse } from \"@gpc-cli/api\";\n\nexport async function convertRegionPrices(\n client: PlayApiClient,\n packageName: string,\n currencyCode: string,\n amount: string,\n): Promise<ConvertRegionPricesResponse> {\n const units = amount.split(\".\")[0] || \"0\";\n const fractional = amount.split(\".\")[1] || \"0\";\n const nanos = Number(fractional.padEnd(9, \"0\").slice(0, 9));\n\n return client.monetization.convertRegionPrices(packageName, {\n price: {\n currencyCode,\n units,\n nanos,\n },\n });\n}\n","import type { PlayApiClient, ReportBucket, ReportType, StatsDimension } from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\n\nconst FINANCIAL_REPORT_TYPES: ReadonlySet<string> = new Set([\n \"earnings\",\n \"sales\",\n \"estimated_sales\",\n \"play_balance\",\n]);\n\nconst STATS_REPORT_TYPES: ReadonlySet<string> = new Set([\n \"installs\",\n \"crashes\",\n \"ratings\",\n \"reviews\",\n \"store_performance\",\n \"subscriptions\",\n]);\n\nconst VALID_DIMENSIONS: ReadonlySet<string> = new Set([\n \"country\",\n \"language\",\n \"os_version\",\n \"device\",\n \"app_version\",\n \"carrier\",\n \"overview\",\n]);\n\nexport function isFinancialReportType(type: string): boolean {\n return FINANCIAL_REPORT_TYPES.has(type);\n}\n\nexport function isStatsReportType(type: string): boolean {\n return STATS_REPORT_TYPES.has(type);\n}\n\nexport function isValidReportType(type: string): type is ReportType {\n return FINANCIAL_REPORT_TYPES.has(type) || STATS_REPORT_TYPES.has(type);\n}\n\nexport function isValidStatsDimension(dim: string): dim is StatsDimension {\n return VALID_DIMENSIONS.has(dim);\n}\n\nexport interface ParsedMonth {\n year: number;\n month: number;\n}\n\nexport function parseMonth(monthStr: string): ParsedMonth {\n const match = /^(\\d{4})-(\\d{2})$/.exec(monthStr);\n if (!match) {\n throw new GpcError(\n `Invalid month format \"${monthStr}\". Expected YYYY-MM (e.g., 2026-03).`,\n \"REPORT_INVALID_MONTH\",\n 2,\n \"Use the format YYYY-MM, for example: --month 2026-03\",\n );\n }\n const year = Number(match[1]);\n const month = Number(match[2]);\n if (month < 1 || month > 12) {\n throw new GpcError(\n `Invalid month \"${month}\". Must be between 01 and 12.`,\n \"REPORT_INVALID_MONTH\",\n 2,\n \"The month value must be between 01 and 12.\",\n );\n }\n return { year, month };\n}\n\nexport async function listReports(\n _client: PlayApiClient,\n _packageName: string,\n reportType: ReportType,\n _year: number,\n _month: number,\n): Promise<ReportBucket[]> {\n throw new GpcError(\n `Report listing for \"${reportType}\" is not available through the Google Play Developer API.`,\n \"REPORT_NOT_SUPPORTED\",\n 1,\n isFinancialReportType(reportType)\n ? \"Financial reports are delivered via Google Cloud Storage. Access them from Play Console → Download reports → Financial.\"\n : \"Stats reports are delivered via Google Cloud Storage. For real-time metrics, use 'gpc vitals' commands.\",\n );\n}\n\nexport async function downloadReport(\n _client: PlayApiClient,\n _packageName: string,\n reportType: ReportType,\n _year: number,\n _month: number,\n): Promise<string> {\n throw new GpcError(\n `Report download for \"${reportType}\" is not available through the Google Play Developer API.`,\n \"REPORT_NOT_SUPPORTED\",\n 1,\n isFinancialReportType(reportType)\n ? \"Financial reports are delivered via Google Cloud Storage. Access them from Play Console → Download reports → Financial.\"\n : \"Stats reports are delivered via Google Cloud Storage. For real-time metrics, use 'gpc vitals' commands.\",\n );\n}\n","import type { UsersApiClient, User, DeveloperPermission, Grant } from \"@gpc-cli/api\";\nimport { paginateAll } from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\n\nexport const PERMISSION_PROPAGATION_WARNING =\n \"Note: Permission changes may take up to 48 hours to propagate.\";\n\nexport interface ListUsersOptions {\n pageToken?: string;\n pageSize?: number;\n limit?: number;\n nextPage?: string;\n}\n\nexport async function listUsers(\n client: UsersApiClient,\n developerId: string,\n options?: ListUsersOptions,\n): Promise<{ users: User[]; nextPageToken?: string }> {\n if (options?.limit || options?.nextPage) {\n const result = await paginateAll<User>(\n async (pageToken) => {\n const resp = await client.list(developerId, { pageToken, pageSize: options?.pageSize });\n return { items: resp.users || [], nextPageToken: resp.nextPageToken };\n },\n { limit: options.limit, startPageToken: options.nextPage },\n );\n return { users: result.items, nextPageToken: result.nextPageToken };\n }\n const response = await client.list(developerId, options);\n return { users: response.users || [], nextPageToken: response.nextPageToken };\n}\n\nexport async function getUser(\n client: UsersApiClient,\n developerId: string,\n userId: string,\n): Promise<User> {\n return client.get(developerId, userId);\n}\n\nexport async function inviteUser(\n client: UsersApiClient,\n developerId: string,\n email: string,\n permissions?: DeveloperPermission[],\n grants?: Grant[],\n): Promise<User> {\n const user: Partial<User> = { email };\n if (permissions) user.developerAccountPermission = permissions;\n if (grants) user.grants = grants;\n return client.create(developerId, user);\n}\n\nexport async function updateUser(\n client: UsersApiClient,\n developerId: string,\n userId: string,\n permissions?: DeveloperPermission[],\n grants?: Grant[],\n): Promise<User> {\n const updates: Partial<User> = {};\n const masks: string[] = [];\n\n if (permissions) {\n updates.developerAccountPermission = permissions;\n masks.push(\"developerAccountPermission\");\n }\n if (grants) {\n updates.grants = grants;\n masks.push(\"grants\");\n }\n\n const updateMask = masks.length > 0 ? masks.join(\",\") : undefined;\n return client.update(developerId, userId, updates, updateMask);\n}\n\nexport async function removeUser(\n client: UsersApiClient,\n developerId: string,\n userId: string,\n): Promise<void> {\n return client.delete(developerId, userId);\n}\n\nexport function parseGrantArg(grantStr: string): Grant {\n const colonIdx = grantStr.indexOf(\":\");\n if (colonIdx === -1) {\n throw new GpcError(\n `Invalid grant format \"${grantStr}\". Expected <packageName>:<PERMISSION>[,<PERMISSION>...]`,\n \"USER_INVALID_GRANT\",\n 2,\n \"Use the format: com.example.app:VIEW_APP_INFORMATION,MANAGE_STORE_LISTING\",\n );\n }\n const packageName = grantStr.slice(0, colonIdx);\n const perms = grantStr.slice(colonIdx + 1).split(\",\") as DeveloperPermission[];\n return { packageName, appLevelPermissions: perms };\n}\n","import type { UsersApiClient } from \"@gpc-cli/api\";\nimport type { Grant } from \"@gpc-cli/api\";\n\nexport async function listGrants(\n client: UsersApiClient,\n developerId: string,\n email: string,\n): Promise<Grant[]> {\n const result = await client.grants.list(developerId, email);\n return result.grants || [];\n}\n\nexport async function createGrant(\n client: UsersApiClient,\n developerId: string,\n email: string,\n packageName: string,\n permissions: string[],\n): Promise<Grant> {\n return client.grants.create(developerId, email, {\n packageName,\n appLevelPermissions: permissions as Grant[\"appLevelPermissions\"],\n });\n}\n\nexport async function updateGrant(\n client: UsersApiClient,\n developerId: string,\n email: string,\n packageName: string,\n permissions: string[],\n): Promise<Grant> {\n return client.grants.patch(\n developerId,\n email,\n packageName,\n {\n appLevelPermissions: permissions as Grant[\"appLevelPermissions\"],\n },\n \"appLevelPermissions\",\n );\n}\n\nexport async function deleteGrant(\n client: UsersApiClient,\n developerId: string,\n email: string,\n packageName: string,\n): Promise<void> {\n return client.grants.delete(developerId, email, packageName);\n}\n","import type { PlayApiClient, Testers } from \"@gpc-cli/api\";\nimport { readFile } from \"node:fs/promises\";\nimport { GpcError } from \"../errors.js\";\n\nexport async function listTesters(\n client: PlayApiClient,\n packageName: string,\n track: string,\n): Promise<Testers> {\n const edit = await client.edits.insert(packageName);\n try {\n const testers = await client.testers.get(packageName, edit.id, track);\n return testers;\n } finally {\n await client.edits.delete(packageName, edit.id);\n }\n}\n\nexport async function addTesters(\n client: PlayApiClient,\n packageName: string,\n track: string,\n groupEmails: string[],\n): Promise<Testers> {\n const edit = await client.edits.insert(packageName);\n try {\n const current = await client.testers.get(packageName, edit.id, track);\n const existing = new Set(current.googleGroups || []);\n for (const email of groupEmails) {\n existing.add(email.trim());\n }\n const updated = await client.testers.update(packageName, edit.id, track, {\n googleGroups: [...existing],\n });\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n return updated;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function removeTesters(\n client: PlayApiClient,\n packageName: string,\n track: string,\n groupEmails: string[],\n): Promise<Testers> {\n const edit = await client.edits.insert(packageName);\n try {\n const current = await client.testers.get(packageName, edit.id, track);\n const toRemove = new Set(groupEmails.map((e) => e.trim()));\n const filtered = (current.googleGroups || []).filter((g) => !toRemove.has(g));\n const updated = await client.testers.update(packageName, edit.id, track, {\n googleGroups: filtered,\n });\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n return updated;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function importTestersFromCsv(\n client: PlayApiClient,\n packageName: string,\n track: string,\n csvPath: string,\n): Promise<{ added: number; testers: Testers }> {\n const content = await readFile(csvPath, \"utf-8\");\n const emails = content\n .split(/[,\\n\\r]+/)\n .map((e) => e.trim())\n .filter((e) => e.length > 0 && e.includes(\"@\"));\n\n if (emails.length === 0) {\n throw new GpcError(\n `No valid email addresses found in ${csvPath}.`,\n \"TESTER_NO_EMAILS\",\n 1,\n \"The CSV file must contain email addresses separated by commas or newlines. Each email must contain an @ symbol.\",\n );\n }\n\n const testers = await addTesters(client, packageName, track, emails);\n return { added: emails.length, testers };\n}\n","import { execFile as execFileCb } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { GpcError } from \"../errors.js\";\n\nconst execFile = promisify(execFileCb);\n\nexport interface GitNotesOptions {\n since?: string;\n language?: string;\n maxLength?: number;\n}\n\nexport interface GitReleaseNotes {\n language: string;\n text: string;\n commitCount: number;\n since: string;\n truncated: boolean;\n}\n\ninterface ParsedCommit {\n type: string;\n message: string;\n}\n\nconst COMMIT_TYPE_HEADERS: Record<string, string> = {\n feat: \"New\",\n fix: \"Fixed\",\n perf: \"Improved\",\n};\n\nconst DEFAULT_MAX_LENGTH = 500;\n\nfunction parseConventionalCommit(subject: string): ParsedCommit {\n const match = subject.match(/^(\\w+)(?:\\([^)]*\\))?:\\s*(.+)$/);\n if (match) {\n return { type: match[1] ?? \"other\", message: (match[2] ?? \"\").trim() };\n }\n return { type: \"other\", message: subject.trim() };\n}\n\nfunction formatNotes(\n commits: ParsedCommit[],\n maxLength: number,\n): { text: string; truncated: boolean } {\n const groups = new Map<string, string[]>();\n\n for (const commit of commits) {\n const header = COMMIT_TYPE_HEADERS[commit.type] || \"Changes\";\n if (!groups.has(header)) {\n groups.set(header, []);\n }\n groups.get(header)?.push(commit.message);\n }\n\n // Order: New, Fixed, Improved, then Changes\n const order = [\"New\", \"Fixed\", \"Improved\", \"Changes\"];\n const sections: string[] = [];\n\n for (const header of order) {\n const items = groups.get(header);\n if (!items || items.length === 0) continue;\n const bullets = items.map((m) => `\\u2022 ${m}`).join(\"\\n\");\n sections.push(`${header}:\\n${bullets}`);\n }\n\n let text = sections.join(\"\\n\\n\");\n let truncated = false;\n\n if (text.length > maxLength) {\n text = text.slice(0, maxLength - 3) + \"...\";\n truncated = true;\n }\n\n return { text, truncated };\n}\n\nasync function gitExec(args: string[]): Promise<string> {\n try {\n const { stdout } = await execFile(\"git\", args);\n return stdout.trim();\n } catch (error: unknown) {\n const err = error as { code?: string; stderr?: string; message?: string };\n if (err.code === \"ENOENT\") {\n throw new GpcError(\n \"git is not available on this system\",\n \"GIT_NOT_FOUND\",\n 1,\n \"Install git and ensure it is in your PATH.\",\n );\n }\n throw error;\n }\n}\n\nexport async function generateNotesFromGit(options?: GitNotesOptions): Promise<GitReleaseNotes> {\n const language = options?.language || \"en-US\";\n const maxLength = options?.maxLength ?? DEFAULT_MAX_LENGTH;\n let since = options?.since;\n\n if (!since) {\n try {\n since = await gitExec([\"describe\", \"--tags\", \"--abbrev=0\"]);\n } catch (e) {\n if (e instanceof GpcError && e.code === \"GIT_NOT_FOUND\") throw e;\n throw new GpcError(\n \"No git tags found. Cannot determine commit range for release notes.\",\n \"GIT_NO_TAGS\",\n 1,\n \"Create a tag first (e.g., git tag v1.0.0) or use --since <ref> to specify a starting point.\",\n );\n }\n }\n\n let logOutput: string;\n try {\n logOutput = await gitExec([\"log\", `${since}..HEAD`, \"--format=%s\"]);\n } catch (error: unknown) {\n const err = error as { stderr?: string; message?: string };\n const msg = err.stderr || err.message || String(error);\n throw new GpcError(\n `Failed to read git log from \"${since}\": ${msg}`,\n \"GIT_LOG_FAILED\",\n 1,\n `Verify that \"${since}\" is a valid git ref (tag, branch, or SHA).`,\n );\n }\n\n if (!logOutput) {\n return {\n language,\n text: \"No changes since last release.\",\n commitCount: 0,\n since,\n truncated: false,\n };\n }\n\n const subjects = logOutput.split(\"\\n\").filter((line) => line.length > 0);\n const commits = subjects.map(parseConventionalCommit);\n const { text, truncated } = formatNotes(commits, maxLength);\n\n return {\n language,\n text,\n commitCount: subjects.length,\n since,\n truncated,\n };\n}\n","import type {\n PlayApiClient,\n AppRecoveryAction,\n AppRecoveryTargeting,\n CreateAppRecoveryActionRequest,\n} from \"@gpc-cli/api\";\n\nexport async function listRecoveryActions(\n client: PlayApiClient,\n packageName: string,\n versionCode?: number,\n): Promise<AppRecoveryAction[]> {\n return client.appRecovery.list(packageName, versionCode);\n}\n\nexport async function cancelRecoveryAction(\n client: PlayApiClient,\n packageName: string,\n recoveryId: string,\n): Promise<void> {\n return client.appRecovery.cancel(packageName, recoveryId);\n}\n\nexport async function deployRecoveryAction(\n client: PlayApiClient,\n packageName: string,\n recoveryId: string,\n): Promise<void> {\n return client.appRecovery.deploy(packageName, recoveryId);\n}\n\nexport async function createRecoveryAction(\n client: PlayApiClient,\n packageName: string,\n request: CreateAppRecoveryActionRequest,\n): Promise<AppRecoveryAction> {\n return client.appRecovery.create(packageName, request);\n}\n\nexport async function addRecoveryTargeting(\n client: PlayApiClient,\n packageName: string,\n actionId: string,\n targeting: AppRecoveryTargeting,\n): Promise<AppRecoveryAction> {\n return client.appRecovery.addTargeting(packageName, actionId, targeting);\n}\n","import type { PlayApiClient, DataSafety } from \"@gpc-cli/api\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { GpcError } from \"../errors.js\";\n\nexport async function getDataSafety(\n client: PlayApiClient,\n packageName: string,\n): Promise<DataSafety> {\n return client.dataSafety.get(packageName);\n}\n\nexport async function updateDataSafety(\n client: PlayApiClient,\n packageName: string,\n data: DataSafety,\n): Promise<DataSafety> {\n return client.dataSafety.update(packageName, data);\n}\n\nexport async function exportDataSafety(\n client: PlayApiClient,\n packageName: string,\n outputPath: string,\n): Promise<DataSafety> {\n const dataSafety = await getDataSafety(client, packageName);\n await writeFile(outputPath, JSON.stringify(dataSafety, null, 2) + \"\\n\", \"utf-8\");\n return dataSafety;\n}\n\nexport async function importDataSafety(\n client: PlayApiClient,\n packageName: string,\n filePath: string,\n): Promise<DataSafety> {\n const content = await readFile(filePath, \"utf-8\");\n let data: DataSafety;\n try {\n data = JSON.parse(content) as DataSafety;\n } catch {\n throw new GpcError(\n `Failed to parse data safety JSON from \"${filePath}\"`,\n \"INVALID_JSON\",\n 1,\n \"Ensure the file contains valid JSON matching the data safety schema.\",\n );\n }\n return updateDataSafety(client, packageName, data);\n}\n","import type { PlayApiClient, ExternalTransaction, ExternalTransactionRefund } from \"@gpc-cli/api\";\n\nexport async function createExternalTransaction(\n client: PlayApiClient,\n packageName: string,\n data: ExternalTransaction,\n): Promise<ExternalTransaction> {\n return client.externalTransactions.create(packageName, data);\n}\n\nexport async function getExternalTransaction(\n client: PlayApiClient,\n packageName: string,\n transactionId: string,\n): Promise<ExternalTransaction> {\n return client.externalTransactions.get(packageName, transactionId);\n}\n\nexport async function refundExternalTransaction(\n client: PlayApiClient,\n packageName: string,\n transactionId: string,\n refundData: ExternalTransactionRefund,\n): Promise<ExternalTransaction> {\n return client.externalTransactions.refund(packageName, transactionId, refundData);\n}\n","import type { PlayApiClient, DeviceTierConfig } from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\n\nexport async function listDeviceTiers(\n client: PlayApiClient,\n packageName: string,\n): Promise<DeviceTierConfig[]> {\n if (!packageName) {\n throw new GpcError(\n \"Package name is required\",\n \"MISSING_PACKAGE_NAME\",\n 2,\n \"Provide a package name with --app or set it in config.\",\n );\n }\n return client.deviceTiers.list(packageName);\n}\n\nexport async function getDeviceTier(\n client: PlayApiClient,\n packageName: string,\n configId: string,\n): Promise<DeviceTierConfig> {\n if (!packageName) {\n throw new GpcError(\n \"Package name is required\",\n \"MISSING_PACKAGE_NAME\",\n 2,\n \"Provide a package name with --app or set it in config.\",\n );\n }\n if (!configId) {\n throw new GpcError(\n \"Config ID is required\",\n \"MISSING_CONFIG_ID\",\n 2,\n \"Provide a device tier config ID.\",\n );\n }\n return client.deviceTiers.get(packageName, configId);\n}\n\nexport async function createDeviceTier(\n client: PlayApiClient,\n packageName: string,\n config: DeviceTierConfig,\n): Promise<DeviceTierConfig> {\n if (!packageName) {\n throw new GpcError(\n \"Package name is required\",\n \"MISSING_PACKAGE_NAME\",\n 2,\n \"Provide a package name with --app or set it in config.\",\n );\n }\n if (!config || !config.deviceGroups || config.deviceGroups.length === 0) {\n throw new GpcError(\n \"Device tier config must include at least one device group\",\n \"INVALID_DEVICE_TIER_CONFIG\",\n 2,\n \"Provide a valid config with deviceGroups.\",\n );\n }\n return client.deviceTiers.create(packageName, config);\n}\n","import type {\n PlayApiClient,\n OneTimeProduct,\n OneTimeProductsListResponse,\n OneTimeOffer,\n OneTimeOffersListResponse,\n} from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\n\nexport async function listOneTimeProducts(\n client: PlayApiClient,\n packageName: string,\n): Promise<OneTimeProductsListResponse> {\n try {\n return await client.oneTimeProducts.list(packageName);\n } catch (error) {\n throw new GpcError(\n `Failed to list one-time products: ${error instanceof Error ? error.message : String(error)}`,\n \"OTP_LIST_FAILED\",\n 4,\n \"Check your package name and API credentials.\",\n );\n }\n}\n\nexport async function getOneTimeProduct(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n): Promise<OneTimeProduct> {\n try {\n return await client.oneTimeProducts.get(packageName, productId);\n } catch (error) {\n throw new GpcError(\n `Failed to get one-time product \"${productId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"OTP_GET_FAILED\",\n 4,\n \"Check that the product ID exists.\",\n );\n }\n}\n\nexport async function createOneTimeProduct(\n client: PlayApiClient,\n packageName: string,\n data: OneTimeProduct,\n): Promise<OneTimeProduct> {\n try {\n return await client.oneTimeProducts.create(packageName, data);\n } catch (error) {\n throw new GpcError(\n `Failed to create one-time product: ${error instanceof Error ? error.message : String(error)}`,\n \"OTP_CREATE_FAILED\",\n 4,\n \"Verify the product data and ensure the product ID is unique.\",\n );\n }\n}\n\nconst OTP_ID_FIELDS = new Set([\"productId\", \"packageName\"]);\n\nfunction deriveOtpUpdateMask(data: Partial<OneTimeProduct>): string {\n return Object.keys(data)\n .filter((k) => !OTP_ID_FIELDS.has(k))\n .join(\",\");\n}\n\nconst OTP_OFFER_ID_FIELDS = new Set([\"productId\", \"offerId\"]);\n\nfunction deriveOtpOfferUpdateMask(data: Partial<OneTimeOffer>): string {\n return Object.keys(data)\n .filter((k) => !OTP_OFFER_ID_FIELDS.has(k))\n .join(\",\");\n}\n\nexport async function updateOneTimeProduct(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n data: Partial<OneTimeProduct>,\n updateMask?: string,\n): Promise<OneTimeProduct> {\n try {\n const mask = updateMask || deriveOtpUpdateMask(data);\n return await client.oneTimeProducts.update(packageName, productId, data, mask);\n } catch (error) {\n throw new GpcError(\n `Failed to update one-time product \"${productId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"OTP_UPDATE_FAILED\",\n 4,\n \"Check that the product ID exists and the data is valid.\",\n );\n }\n}\n\nexport async function deleteOneTimeProduct(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n): Promise<void> {\n try {\n await client.oneTimeProducts.delete(packageName, productId);\n } catch (error) {\n throw new GpcError(\n `Failed to delete one-time product \"${productId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"OTP_DELETE_FAILED\",\n 4,\n \"Check that the product ID exists and is not active.\",\n );\n }\n}\n\nexport async function listOneTimeOffers(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n): Promise<OneTimeOffersListResponse> {\n try {\n return await client.oneTimeProducts.listOffers(packageName, productId);\n } catch (error) {\n throw new GpcError(\n `Failed to list offers for product \"${productId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"OTP_OFFERS_LIST_FAILED\",\n 4,\n \"Check the product ID and your API credentials.\",\n );\n }\n}\n\nexport async function getOneTimeOffer(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n offerId: string,\n): Promise<OneTimeOffer> {\n try {\n return await client.oneTimeProducts.getOffer(packageName, productId, offerId);\n } catch (error) {\n throw new GpcError(\n `Failed to get offer \"${offerId}\" for product \"${productId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"OTP_OFFER_GET_FAILED\",\n 4,\n \"Check that the product and offer IDs exist.\",\n );\n }\n}\n\nexport async function createOneTimeOffer(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n data: OneTimeOffer,\n): Promise<OneTimeOffer> {\n try {\n return await client.oneTimeProducts.createOffer(packageName, productId, data);\n } catch (error) {\n throw new GpcError(\n `Failed to create offer for product \"${productId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"OTP_OFFER_CREATE_FAILED\",\n 4,\n \"Verify the offer data and ensure the offer ID is unique.\",\n );\n }\n}\n\nexport async function updateOneTimeOffer(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n offerId: string,\n data: Partial<OneTimeOffer>,\n updateMask?: string,\n): Promise<OneTimeOffer> {\n try {\n const mask = updateMask || deriveOtpOfferUpdateMask(data);\n return await client.oneTimeProducts.updateOffer(packageName, productId, offerId, data, mask);\n } catch (error) {\n throw new GpcError(\n `Failed to update offer \"${offerId}\" for product \"${productId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"OTP_OFFER_UPDATE_FAILED\",\n 4,\n \"Check that the product and offer IDs exist and the data is valid.\",\n );\n }\n}\n\nexport interface OneTimeProductDiff {\n field: string;\n local: string;\n remote: string;\n}\n\nexport async function diffOneTimeProduct(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n localData: OneTimeProduct,\n): Promise<OneTimeProductDiff[]> {\n const remote = await client.oneTimeProducts.get(packageName, productId);\n const diffs: OneTimeProductDiff[] = [];\n const fieldsToCompare = [\"listings\", \"purchaseType\", \"taxAndComplianceSettings\"];\n\n for (const field of fieldsToCompare) {\n const localVal = JSON.stringify(\n (localData as unknown as Record<string, unknown>)[field] ?? null,\n );\n const remoteVal = JSON.stringify((remote as unknown as Record<string, unknown>)[field] ?? null);\n if (localVal !== remoteVal) {\n diffs.push({ field, local: localVal, remote: remoteVal });\n }\n }\n return diffs;\n}\n\nexport async function deleteOneTimeOffer(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n offerId: string,\n): Promise<void> {\n try {\n await client.oneTimeProducts.deleteOffer(packageName, productId, offerId);\n } catch (error) {\n throw new GpcError(\n `Failed to delete offer \"${offerId}\" for product \"${productId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"OTP_OFFER_DELETE_FAILED\",\n 4,\n \"Check that the product and offer IDs exist.\",\n );\n }\n}\n","import process from \"node:process\";\n\nconst FRAMES = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\nconst INTERVAL_MS = 80;\n\nexport interface Spinner {\n start(): void;\n stop(message?: string): void;\n fail(message?: string): void;\n update(message: string): void;\n}\n\nexport function createSpinner(message: string): Spinner {\n const isTTY = process.stderr.isTTY === true;\n let frameIndex = 0;\n let timer: ReturnType<typeof setInterval> | undefined;\n let currentMessage = message;\n let started = false;\n\n function clearLine(): void {\n if (isTTY) {\n process.stderr.write(\"\\r\\x1b[K\");\n }\n }\n\n function renderFrame(): void {\n const frame = FRAMES[frameIndex % FRAMES.length];\n process.stderr.write(`\\r\\x1b[K${frame} ${currentMessage}`);\n frameIndex++;\n }\n\n return {\n start(): void {\n if (started) return;\n started = true;\n\n if (!isTTY) {\n process.stderr.write(`${currentMessage}\\n`);\n return;\n }\n\n renderFrame();\n timer = setInterval(renderFrame, INTERVAL_MS);\n },\n\n stop(msg?: string): void {\n if (timer) {\n clearInterval(timer);\n timer = undefined;\n }\n const text = msg ?? currentMessage;\n if (isTTY) {\n clearLine();\n process.stderr.write(`\\u2714 ${text}\\n`);\n } else if (!started) {\n process.stderr.write(`${text}\\n`);\n }\n started = false;\n },\n\n fail(msg?: string): void {\n if (timer) {\n clearInterval(timer);\n timer = undefined;\n }\n const text = msg ?? currentMessage;\n if (isTTY) {\n clearLine();\n process.stderr.write(`\\u2718 ${text}\\n`);\n } else if (!started) {\n process.stderr.write(`${text}\\n`);\n }\n started = false;\n },\n\n update(msg: string): void {\n currentMessage = msg;\n if (!isTTY || !started) return;\n renderFrame();\n },\n };\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { getCacheDir } from \"@gpc-cli/config\";\n\nexport interface TrainStage {\n track: string;\n rollout: number;\n /** ISO 8601 duration or human string like \"2d\", \"7d\" */\n after?: string;\n}\n\nexport interface TrainGates {\n crashes?: { max: number };\n anr?: { max: number };\n}\n\nexport interface TrainConfig {\n stages: TrainStage[];\n gates?: TrainGates;\n}\n\nexport type TrainStatus = \"idle\" | \"running\" | \"paused\" | \"completed\" | \"aborted\";\n\nexport interface TrainState {\n packageName: string;\n status: TrainStatus;\n currentStage: number;\n startedAt?: string;\n updatedAt: string;\n stages: Array<\n TrainStage & {\n executedAt?: string;\n scheduledAt?: string;\n }\n >;\n gates?: TrainGates;\n}\n\nfunction stateFile(packageName: string): string {\n return join(getCacheDir(), `train-${packageName}.json`);\n}\n\nexport async function readTrainState(packageName: string): Promise<TrainState | null> {\n const path = stateFile(packageName);\n try {\n const raw = await readFile(path, \"utf-8\");\n return JSON.parse(raw) as TrainState;\n } catch {\n return null;\n }\n}\n\nexport async function writeTrainState(packageName: string, state: TrainState): Promise<void> {\n const path = stateFile(packageName);\n const dir = dirname(path);\n await mkdir(dir, { recursive: true });\n await writeFile(path, JSON.stringify(state, null, 2), \"utf-8\");\n}\n\nexport async function clearTrainState(packageName: string): Promise<void> {\n const { unlink } = await import(\"node:fs/promises\");\n const path = stateFile(packageName);\n await unlink(path).catch(() => {});\n}\n\n/** Parse a duration string like \"2d\", \"7d\", \"1h\" into milliseconds. */\nexport function parseDuration(s: string): number {\n const match = /^(\\d+)(d|h|m)$/.exec(s.trim());\n if (!match) return 0;\n const n = parseInt(match[1] ?? \"0\", 10);\n switch (match[2]) {\n case \"d\":\n return n * 24 * 60 * 60 * 1000;\n case \"h\":\n return n * 60 * 60 * 1000;\n case \"m\":\n return n * 60 * 1000;\n default:\n return 0;\n }\n}\n","import type { PlayApiClient } from \"@gpc-cli/api\";\nimport type { ReportingApiClient } from \"@gpc-cli/api\";\nimport {\n readTrainState,\n writeTrainState,\n clearTrainState,\n parseDuration,\n} from \"../utils/train-state.js\";\nimport type { TrainConfig, TrainState } from \"../utils/train-state.js\";\nimport { updateRollout } from \"./releases.js\";\nimport { getVitalsCrashes, getVitalsAnr } from \"./vitals.js\";\nimport { GpcError } from \"../errors.js\";\n\nexport type { TrainConfig, TrainState };\n\nexport interface StartTrainOptions {\n force?: boolean;\n}\n\n/** Start or resume a release train for a package. */\nexport async function startTrain(\n apiClient: PlayApiClient,\n packageName: string,\n config: TrainConfig,\n options?: StartTrainOptions,\n): Promise<TrainState> {\n const existing = await readTrainState(packageName);\n\n if (existing && existing.status === \"running\" && !options?.force) {\n return existing;\n }\n\n const now = new Date().toISOString();\n const state: TrainState = {\n packageName,\n status: \"running\",\n currentStage: 0,\n startedAt: now,\n updatedAt: now,\n stages: config.stages.map((s, i) => ({\n ...s,\n scheduledAt: i === 0 ? now : undefined,\n })),\n gates: config.gates,\n };\n\n await writeTrainState(packageName, state);\n\n // Execute stage 0 immediately\n await executeStage(apiClient, packageName, state, 0);\n\n return state;\n}\n\n/** Get current train status. */\nexport async function getTrainStatus(packageName: string): Promise<TrainState | null> {\n return readTrainState(packageName);\n}\n\n/** Pause a running train. */\nexport async function pauseTrain(packageName: string): Promise<TrainState | null> {\n const state = await readTrainState(packageName);\n if (!state || state.status !== \"running\") return state;\n\n state.status = \"paused\";\n state.updatedAt = new Date().toISOString();\n await writeTrainState(packageName, state);\n return state;\n}\n\n/** Abort a train and clear state. */\nexport async function abortTrain(packageName: string): Promise<void> {\n await clearTrainState(packageName);\n}\n\n/** Advance the train to the next eligible stage. */\nexport async function advanceTrain(\n apiClient: PlayApiClient,\n reportingClient: ReportingApiClient,\n packageName: string,\n): Promise<TrainState | null> {\n const state = await readTrainState(packageName);\n if (!state || state.status !== \"running\") return state;\n\n const nextStage = state.currentStage + 1;\n if (nextStage >= state.stages.length) {\n state.status = \"completed\";\n state.updatedAt = new Date().toISOString();\n await writeTrainState(packageName, state);\n return state;\n }\n\n const nextStageConfig = state.stages[nextStage];\n if (!nextStageConfig) return state;\n\n // Check `after` delay\n if (nextStageConfig.after) {\n const delayMs = parseDuration(nextStageConfig.after);\n const currentStageConfig = state.stages[state.currentStage];\n const executedAt = currentStageConfig?.executedAt;\n if (executedAt && delayMs > 0) {\n const elapsed = Date.now() - new Date(executedAt).getTime();\n if (elapsed < delayMs) {\n // Not ready yet — schedule time for info\n const readyAt = new Date(new Date(executedAt).getTime() + delayMs).toISOString();\n nextStageConfig.scheduledAt = readyAt;\n await writeTrainState(packageName, state);\n return state;\n }\n }\n }\n\n // Check vitals gates before advancing\n if (state.gates) {\n if (state.gates.crashes?.max !== undefined) {\n const result = await getVitalsCrashes(reportingClient, packageName, { days: 1 });\n const latestRow = result.rows?.[result.rows.length - 1];\n const firstMetric = latestRow?.metrics ? Object.keys(latestRow.metrics)[0] : undefined;\n const value = firstMetric\n ? Number(latestRow?.metrics[firstMetric]?.decimalValue?.value)\n : undefined;\n if (value !== undefined && value > state.gates.crashes.max / 100) {\n state.status = \"paused\";\n state.updatedAt = new Date().toISOString();\n await writeTrainState(packageName, state);\n throw new GpcError(\n `Crash gate failed: ${(value * 100).toFixed(3)}% > max ${state.gates.crashes.max}%. Train paused.`,\n \"TRAIN_CRASH_GATE_FAILED\",\n 6,\n \"Review crash data with: gpc vitals crashes --days 1\",\n );\n }\n }\n\n if (state.gates.anr?.max !== undefined) {\n const result = await getVitalsAnr(reportingClient, packageName, { days: 1 });\n const latestRow = result.rows?.[result.rows.length - 1];\n const firstMetric = latestRow?.metrics ? Object.keys(latestRow.metrics)[0] : undefined;\n const value = firstMetric\n ? Number(latestRow?.metrics[firstMetric]?.decimalValue?.value)\n : undefined;\n if (value !== undefined && value > state.gates.anr.max / 100) {\n state.status = \"paused\";\n state.updatedAt = new Date().toISOString();\n await writeTrainState(packageName, state);\n throw new GpcError(\n `ANR gate failed: ${(value * 100).toFixed(3)}% > max ${state.gates.anr.max}%. Train paused.`,\n \"TRAIN_ANR_GATE_FAILED\",\n 6,\n \"Review ANR data with: gpc vitals anr --days 1\",\n );\n }\n }\n }\n\n await executeStage(apiClient, packageName, state, nextStage);\n return state;\n}\n\nasync function executeStage(\n apiClient: PlayApiClient,\n packageName: string,\n state: TrainState,\n stageIndex: number,\n): Promise<void> {\n const stage = state.stages[stageIndex];\n if (!stage) throw new GpcError(`Stage ${stageIndex} not found`, \"TRAIN_STAGE_NOT_FOUND\", 1, \"Check your release train configuration.\");\n const rolloutFraction = stage.rollout / 100;\n\n await updateRollout(apiClient, packageName, stage.track, \"increase\", rolloutFraction);\n\n stage.executedAt = new Date().toISOString();\n state.currentStage = stageIndex;\n state.updatedAt = new Date().toISOString();\n await writeTrainState(packageName, state);\n}\n","import type { GamesApiClient, Leaderboard, Achievement, GameEvent } from \"@gpc-cli/api\";\n\nexport { Leaderboard, Achievement, GameEvent };\n\nexport async function listLeaderboards(\n client: GamesApiClient,\n packageName: string,\n): Promise<Leaderboard[]> {\n const result = await client.leaderboards.list(packageName);\n return result.items ?? [];\n}\n\nexport async function listAchievements(\n client: GamesApiClient,\n packageName: string,\n): Promise<Achievement[]> {\n const result = await client.achievements.list(packageName);\n return result.items ?? [];\n}\n\nexport async function listEvents(\n client: GamesApiClient,\n packageName: string,\n): Promise<GameEvent[]> {\n const result = await client.events.list(packageName);\n return result.items ?? [];\n}\n","import type { EnterpriseApiClient, CustomApp } from \"@gpc-cli/api\";\n\nexport { CustomApp };\n\nexport async function listEnterpriseApps(\n client: EnterpriseApiClient,\n organizationId: string,\n): Promise<CustomApp[]> {\n const result = await client.apps.list(organizationId);\n return result.customApps ?? [];\n}\n\nexport async function createEnterpriseApp(\n client: EnterpriseApiClient,\n organizationId: string,\n app: Partial<CustomApp>,\n): Promise<CustomApp> {\n return client.apps.create(organizationId, app);\n}\n","import { appendFile, chmod, mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport interface AuditEntry {\n timestamp: string;\n command: string;\n app?: string;\n args: Record<string, unknown>;\n user?: string;\n success?: boolean;\n durationMs?: number;\n error?: string;\n}\n\nlet auditDir: string | null = null;\n\n/**\n * Initialize audit logging with a directory path.\n * Typically ~/.config/gpc/ or the XDG config dir.\n */\nexport function initAudit(configDir: string): void {\n auditDir = configDir;\n}\n\n/**\n * Write an audit log entry. Non-blocking — errors are silently ignored.\n */\nexport async function writeAuditLog(entry: AuditEntry): Promise<void> {\n if (!auditDir) return;\n\n try {\n await mkdir(auditDir, { recursive: true, mode: 0o700 });\n const logPath = join(auditDir, \"audit.log\");\n const redactedEntry = redactAuditArgs(entry);\n const line = JSON.stringify(redactedEntry) + \"\\n\";\n await appendFile(logPath, line, { encoding: \"utf-8\", mode: 0o600 });\n await chmod(logPath, 0o600).catch(() => {});\n } catch {\n // Audit logging must never break the CLI\n }\n}\n\nconst SENSITIVE_ARG_KEYS = new Set([\n \"keyFile\",\n \"key_file\",\n \"serviceAccount\",\n \"service-account\",\n \"token\",\n \"password\",\n \"secret\",\n \"credentials\",\n \"private_key\",\n \"privateKey\",\n \"private_key_id\",\n \"privateKeyId\",\n \"client_secret\",\n \"clientSecret\",\n \"accessToken\",\n \"access_token\",\n \"refreshToken\",\n \"refresh_token\",\n \"apiKey\",\n \"api_key\",\n \"auth_token\",\n \"bearer\",\n \"jwt\",\n \"signing_key\",\n \"keystore_password\",\n \"store_password\",\n \"key_password\",\n]);\n\nexport { SENSITIVE_ARG_KEYS };\n\nexport function redactAuditArgs(entry: AuditEntry): AuditEntry {\n const redacted: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(entry.args)) {\n redacted[k] = SENSITIVE_ARG_KEYS.has(k) ? \"[REDACTED]\" : v;\n }\n return { ...entry, args: redacted };\n}\n\n/**\n * Convenience: create an audit entry for a write command.\n */\nexport function createAuditEntry(\n command: string,\n args: Record<string, unknown>,\n app?: string,\n): AuditEntry {\n return {\n timestamp: new Date().toISOString(),\n command,\n app,\n args,\n };\n}\n\nexport async function listAuditEvents(options?: {\n limit?: number;\n since?: string;\n command?: string;\n}): Promise<AuditEntry[]> {\n if (!auditDir) return [];\n const logPath = join(auditDir, \"audit.log\");\n let content: string;\n try {\n content = await readFile(logPath, \"utf-8\");\n } catch {\n return [];\n }\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n let entries: AuditEntry[] = [];\n for (const line of lines) {\n try {\n entries.push(JSON.parse(line) as AuditEntry);\n } catch {\n // skip malformed lines\n }\n }\n if (options?.since) {\n const sinceDate = new Date(options.since).getTime();\n entries = entries.filter((e) => new Date(e.timestamp).getTime() >= sinceDate);\n }\n if (options?.command) {\n const cmd = options.command.toLowerCase();\n entries = entries.filter((e) => e.command.toLowerCase().includes(cmd));\n }\n if (options?.limit) {\n entries = entries.slice(-options.limit);\n }\n return entries;\n}\n\nexport async function searchAuditEvents(query: string): Promise<AuditEntry[]> {\n const all = await listAuditEvents();\n const q = query.toLowerCase();\n return all.filter((e) => {\n const text = JSON.stringify(e).toLowerCase();\n return text.includes(q);\n });\n}\n\nexport async function clearAuditLog(options?: {\n before?: string;\n dryRun?: boolean;\n}): Promise<{ deleted: number; remaining: number }> {\n if (!auditDir) return { deleted: 0, remaining: 0 };\n const logPath = join(auditDir, \"audit.log\");\n let content: string;\n try {\n content = await readFile(logPath, \"utf-8\");\n } catch {\n return { deleted: 0, remaining: 0 };\n }\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n if (!options?.before) {\n const count = lines.length;\n if (!options?.dryRun) {\n await writeFile(logPath, \"\", { encoding: \"utf-8\", mode: 0o600 });\n }\n return { deleted: count, remaining: 0 };\n }\n const beforeDate = new Date(options.before).getTime();\n const keep: string[] = [];\n const remove: string[] = [];\n for (const line of lines) {\n try {\n const entry = JSON.parse(line) as AuditEntry;\n if (new Date(entry.timestamp).getTime() < beforeDate) {\n remove.push(line);\n } else {\n keep.push(line);\n }\n } catch {\n keep.push(line);\n }\n }\n if (!options?.dryRun) {\n await writeFile(logPath, keep.length > 0 ? keep.join(\"\\n\") + \"\\n\" : \"\", {\n encoding: \"utf-8\",\n mode: 0o600,\n });\n }\n return { deleted: remove.length, remaining: keep.length };\n}\n","import { listAuditEvents } from \"../audit.js\";\n\nexport interface QuotaUsage {\n dailyCallsUsed: number;\n dailyCallsLimit: number;\n dailyCallsRemaining: number;\n minuteCallsUsed: number;\n minuteCallsLimit: number;\n minuteCallsRemaining: number;\n topCommands: Array<{ command: string; count: number }>;\n}\n\nconst DAILY_LIMIT = 200_000;\nconst MINUTE_LIMIT = 3_000;\n\n/** Compute quota usage from the local audit log. */\nexport async function getQuotaUsage(): Promise<QuotaUsage> {\n const now = Date.now();\n const startOfDay = new Date(now);\n startOfDay.setUTCHours(0, 0, 0, 0);\n\n const startOfMinute = new Date(now - 60 * 1000);\n\n const todayEntries = await listAuditEvents({\n since: startOfDay.toISOString(),\n });\n\n const minuteEntries = todayEntries.filter(\n (e) => new Date(e.timestamp).getTime() >= startOfMinute.getTime(),\n );\n\n const commandCounts = new Map<string, number>();\n for (const entry of todayEntries) {\n commandCounts.set(entry.command, (commandCounts.get(entry.command) ?? 0) + 1);\n }\n\n const topCommands = Array.from(commandCounts.entries())\n .map(([command, count]) => ({ command, count }))\n .sort((a, b) => b.count - a.count)\n .slice(0, 10);\n\n const dailyCallsUsed = todayEntries.length;\n const minuteCallsUsed = minuteEntries.length;\n\n return {\n dailyCallsUsed,\n dailyCallsLimit: DAILY_LIMIT,\n dailyCallsRemaining: Math.max(0, DAILY_LIMIT - dailyCallsUsed),\n minuteCallsUsed,\n minuteCallsLimit: MINUTE_LIMIT,\n minuteCallsRemaining: Math.max(0, MINUTE_LIMIT - minuteCallsUsed),\n topCommands,\n };\n}\n","import { resolve, normalize } from \"node:path\";\nimport { GpcError } from \"../errors.js\";\n\n/**\n * Normalize and resolve a user-supplied path.\n * Prevents path traversal by normalizing `.` and `..` components.\n */\nexport function safePath(userPath: string): string {\n return resolve(normalize(userPath));\n}\n\n/**\n * Validate that a resolved path is within an expected base directory.\n * Returns the resolved path or throws if it escapes the base.\n */\nexport function safePathWithin(userPath: string, baseDir: string): string {\n const resolved = safePath(userPath);\n const base = safePath(baseDir);\n\n if (!resolved.startsWith(base + \"/\") && resolved !== base) {\n throw new GpcError(\n `Path \"${userPath}\" resolves outside the expected directory \"${baseDir}\"`,\n \"PATH_TRAVERSAL\",\n 2,\n \"The path must stay within the target directory. Remove any ../ segments or use an absolute path within the expected directory.\",\n );\n }\n\n return resolved;\n}\n","// Named exports only. No default export.\n\nimport { mkdir, writeFile, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport interface InitOptions {\n dir: string;\n app?: string;\n ci?: \"github\" | \"gitlab\";\n skipExisting?: boolean;\n}\n\nexport interface InitResult {\n created: string[];\n skipped: string[];\n}\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function safeWrite(\n filePath: string,\n content: string,\n created: string[],\n skipped: string[],\n skipExisting: boolean,\n): Promise<void> {\n if (await exists(filePath)) {\n if (skipExisting) {\n skipped.push(filePath);\n return;\n }\n }\n const dir = filePath.substring(0, filePath.lastIndexOf(\"/\"));\n await mkdir(dir, { recursive: true });\n await writeFile(filePath, content, \"utf-8\");\n created.push(filePath);\n}\n\nexport async function initProject(options: InitOptions): Promise<InitResult> {\n const { dir, app, ci } = options;\n const skipExisting = options.skipExisting !== false;\n const created: string[] = [];\n const skipped: string[] = [];\n const pkg = app || \"com.example.app\";\n\n // .gpcrc.json\n const gpcrc = JSON.stringify(\n {\n app: pkg,\n output: \"table\",\n },\n null,\n 2,\n );\n await safeWrite(join(dir, \".gpcrc.json\"), gpcrc + \"\\n\", created, skipped, skipExisting);\n\n // .preflightrc.json\n const preflightrc = JSON.stringify(\n {\n failOn: \"error\",\n targetSdkMinimum: 35,\n maxDownloadSizeMb: 150,\n allowedPermissions: [],\n disabledRules: [],\n severityOverrides: {},\n },\n null,\n 2,\n );\n await safeWrite(\n join(dir, \".preflightrc.json\"),\n preflightrc + \"\\n\",\n created,\n skipped,\n skipExisting,\n );\n\n // metadata/android/en-US/ listing files\n const metaDir = join(dir, \"metadata\", \"android\", \"en-US\");\n await safeWrite(join(metaDir, \"title.txt\"), \"\", created, skipped, skipExisting);\n await safeWrite(join(metaDir, \"short_description.txt\"), \"\", created, skipped, skipExisting);\n await safeWrite(join(metaDir, \"full_description.txt\"), \"\", created, skipped, skipExisting);\n await safeWrite(join(metaDir, \"video.txt\"), \"\", created, skipped, skipExisting);\n\n // metadata/android/en-US/images/phoneScreenshots/\n const ssDir = join(metaDir, \"images\", \"phoneScreenshots\");\n await mkdir(ssDir, { recursive: true });\n await safeWrite(join(ssDir, \".gitkeep\"), \"\", created, skipped, skipExisting);\n\n // CI templates\n if (ci === \"github\") {\n const workflow = githubActionsTemplate(pkg);\n const workflowDir = join(dir, \".github\", \"workflows\");\n await safeWrite(join(workflowDir, \"gpc-release.yml\"), workflow, created, skipped, skipExisting);\n } else if (ci === \"gitlab\") {\n const pipeline = gitlabCiTemplate(pkg);\n await safeWrite(join(dir, \".gitlab-ci-gpc.yml\"), pipeline, created, skipped, skipExisting);\n }\n\n return { created, skipped };\n}\n\nfunction githubActionsTemplate(pkg: string): string {\n return `name: GPC Release\non:\n push:\n tags: ['v*']\n\njobs:\n release:\n runs-on: ubuntu-latest\n env:\n GPC_SERVICE_ACCOUNT: \\${{ secrets.GPC_SERVICE_ACCOUNT }}\n GPC_APP: ${pkg}\n steps:\n - uses: actions/checkout@v4\n\n - uses: actions/setup-node@v4\n with:\n node-version: 20\n\n - name: Build\n run: ./gradlew bundleRelease\n\n - name: Install GPC\n run: npm install -g @gpc-cli/cli\n\n - name: Preflight compliance check\n run: gpc preflight app/build/outputs/bundle/release/app-release.aab --fail-on error\n\n - name: Upload to internal track\n run: |\n gpc releases upload app/build/outputs/bundle/release/app-release.aab \\\\\n --track internal \\\\\n --json\n`;\n}\n\nfunction gitlabCiTemplate(pkg: string): string {\n return `# GPC Release Pipeline\n# Add GPC_SERVICE_ACCOUNT as a CI/CD variable (masked, protected)\n\nstages:\n - build\n - preflight\n - release\n\nvariables:\n GPC_APP: ${pkg}\n\nbuild:\n stage: build\n image: gradle:jdk17\n script:\n - ./gradlew bundleRelease\n artifacts:\n paths:\n - app/build/outputs/bundle/release/app-release.aab\n\npreflight:\n stage: preflight\n image: node:20\n script:\n - npm install -g @gpc-cli/cli\n - gpc preflight app/build/outputs/bundle/release/app-release.aab --fail-on error --json\n\nrelease:\n stage: release\n image: node:20\n script:\n - npm install -g @gpc-cli/cli\n - gpc releases upload app/build/outputs/bundle/release/app-release.aab --track internal\n only:\n - tags\n`;\n}\n","// Named exports only. No default export.\n\nexport type FindingSeverity = \"critical\" | \"error\" | \"warning\" | \"info\";\n\n/** Severity ordering for threshold comparisons. */\nexport const SEVERITY_ORDER: Record<FindingSeverity, number> = {\n info: 0,\n warning: 1,\n error: 2,\n critical: 3,\n};\n\nexport interface PreflightFinding {\n /** Scanner name, e.g. \"manifest\", \"permissions\" */\n scanner: string;\n /** Machine-readable rule ID, e.g. \"targetSdk-below-minimum\" */\n ruleId: string;\n severity: FindingSeverity;\n title: string;\n message: string;\n suggestion?: string;\n /** Link to the relevant Google Play policy page */\n policyUrl?: string;\n}\n\nexport interface PreflightContext {\n aabPath?: string;\n manifest?: ParsedManifest;\n zipEntries?: ZipEntryInfo[];\n metadataDir?: string;\n sourceDir?: string;\n config: PreflightConfig;\n}\n\nexport interface PreflightResult {\n scanners: string[];\n findings: PreflightFinding[];\n summary: Record<FindingSeverity, number>;\n passed: boolean;\n durationMs: number;\n}\n\nexport interface PreflightScanner {\n name: string;\n description: string;\n requires: (\"manifest\" | \"zipEntries\" | \"metadataDir\" | \"sourceDir\")[];\n scan(ctx: PreflightContext): Promise<PreflightFinding[]>;\n}\n\nexport interface PreflightConfig {\n failOn: FindingSeverity;\n targetSdkMinimum: number;\n maxDownloadSizeMb: number;\n allowedPermissions: string[];\n disabledRules: string[];\n severityOverrides: Record<string, FindingSeverity>;\n}\n\nexport interface PreflightOptions {\n aabPath?: string;\n metadataDir?: string;\n sourceDir?: string;\n scanners?: string[];\n failOn?: FindingSeverity;\n configPath?: string;\n}\n\nexport interface ParsedManifest {\n packageName: string;\n versionCode: number;\n versionName: string;\n minSdk: number;\n targetSdk: number;\n debuggable: boolean;\n testOnly: boolean;\n usesCleartextTraffic: boolean;\n extractNativeLibs: boolean;\n permissions: string[];\n features: ManifestFeature[];\n activities: ManifestComponent[];\n services: ManifestComponent[];\n receivers: ManifestComponent[];\n providers: ManifestComponent[];\n /** Set when the manifest could not be fully parsed — manifest-dependent scanners should skip. */\n _parseError?: string;\n}\n\nexport interface ManifestFeature {\n name: string;\n required: boolean;\n}\n\nexport interface ManifestComponent {\n name: string;\n exported?: boolean;\n foregroundServiceType?: string;\n hasIntentFilter: boolean;\n}\n\nexport interface ZipEntryInfo {\n path: string;\n compressedSize: number;\n uncompressedSize: number;\n}\n\nexport const DEFAULT_PREFLIGHT_CONFIG: PreflightConfig = {\n failOn: \"error\",\n targetSdkMinimum: 35,\n maxDownloadSizeMb: 150,\n allowedPermissions: [],\n disabledRules: [],\n severityOverrides: {},\n};\n","// Named exports only. No default export.\n\nimport { readFile } from \"node:fs/promises\";\nimport type { PreflightConfig, FindingSeverity } from \"./types.js\";\nimport { DEFAULT_PREFLIGHT_CONFIG } from \"./types.js\";\n\nconst VALID_SEVERITIES = new Set([\"critical\", \"error\", \"warning\", \"info\"]);\n\nexport async function loadPreflightConfig(configPath?: string): Promise<PreflightConfig> {\n const path = configPath || \".preflightrc.json\";\n\n let raw: string;\n try {\n raw = await readFile(path, \"utf-8\");\n } catch {\n return { ...DEFAULT_PREFLIGHT_CONFIG };\n }\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n throw new Error(`Invalid JSON in ${path}. Check the file for syntax errors.`);\n }\n\n const config: PreflightConfig = { ...DEFAULT_PREFLIGHT_CONFIG };\n\n if (typeof parsed[\"failOn\"] === \"string\" && VALID_SEVERITIES.has(parsed[\"failOn\"])) {\n config.failOn = parsed[\"failOn\"] as FindingSeverity;\n }\n\n if (typeof parsed[\"targetSdkMinimum\"] === \"number\" && parsed[\"targetSdkMinimum\"] > 0) {\n config.targetSdkMinimum = parsed[\"targetSdkMinimum\"];\n }\n\n if (typeof parsed[\"maxDownloadSizeMb\"] === \"number\" && parsed[\"maxDownloadSizeMb\"] > 0) {\n config.maxDownloadSizeMb = parsed[\"maxDownloadSizeMb\"];\n }\n\n if (Array.isArray(parsed[\"allowedPermissions\"])) {\n config.allowedPermissions = (parsed[\"allowedPermissions\"] as unknown[]).filter(\n (v): v is string => typeof v === \"string\",\n );\n }\n\n if (Array.isArray(parsed[\"disabledRules\"])) {\n config.disabledRules = (parsed[\"disabledRules\"] as unknown[]).filter(\n (v): v is string => typeof v === \"string\",\n );\n }\n\n if (typeof parsed[\"severityOverrides\"] === \"object\" && parsed[\"severityOverrides\"] !== null) {\n const overrides: Record<string, FindingSeverity> = {};\n for (const [key, val] of Object.entries(\n parsed[\"severityOverrides\"] as Record<string, unknown>,\n )) {\n if (typeof val === \"string\" && VALID_SEVERITIES.has(val)) {\n overrides[key] = val as FindingSeverity;\n }\n }\n config.severityOverrides = overrides;\n }\n\n return config;\n}\n","// Named exports only. No default export.\n\nimport { open as yauzlOpen, type Entry, type ZipFile } from \"yauzl\";\nimport type { ParsedManifest, ZipEntryInfo } from \"./types.js\";\nimport { decodeManifest } from \"./manifest-parser.js\";\n\nconst MANIFEST_PATH = \"base/manifest/AndroidManifest.xml\";\n\ninterface AabContents {\n manifest: ParsedManifest;\n entries: ZipEntryInfo[];\n}\n\n/**\n * Open an AAB file, extract the manifest and ZIP entry list.\n * Uses yauzl for streaming — does not load the entire file into memory.\n */\nexport async function readAab(aabPath: string): Promise<AabContents> {\n const { zipfile, entries, manifestBuf } = await openAndScan(aabPath);\n zipfile.close();\n\n if (!manifestBuf) {\n throw new Error(\n `AAB is missing ${MANIFEST_PATH}. This does not appear to be a valid Android App Bundle.`,\n );\n }\n\n let manifest: ParsedManifest;\n try {\n manifest = decodeManifest(manifestBuf);\n } catch (err) {\n // Some AABs have manifests that protobufjs cannot fully parse\n // (e.g., larger bundles with complex resource tables, ESM/CJS interop issues).\n // Fall back to a minimal manifest so non-manifest scanners can still run.\n const errMsg = err instanceof Error ? err.message : String(err);\n manifest = createFallbackManifest();\n manifest._parseError = `Manifest could not be fully parsed: ${errMsg}. Manifest-dependent checks will be skipped.`;\n }\n\n return { manifest, entries };\n}\n\nfunction createFallbackManifest(): ParsedManifest {\n return {\n packageName: \"\",\n versionCode: 0,\n versionName: \"\",\n minSdk: 0,\n targetSdk: 0,\n debuggable: false,\n testOnly: false,\n usesCleartextTraffic: false,\n extractNativeLibs: true,\n permissions: [],\n features: [],\n activities: [],\n services: [],\n receivers: [],\n providers: [],\n };\n}\n\n/**\n * Open ZIP, iterate entries, collect entry list and manifest buffer.\n * yauzl's lazyEntries mode ensures we control iteration — the \"end\" event\n * only fires after the last readEntry() call with no more entries.\n */\nfunction openAndScan(\n aabPath: string,\n): Promise<{ zipfile: ZipFile; entries: ZipEntryInfo[]; manifestBuf: Buffer | null }> {\n return new Promise((resolve, reject) => {\n yauzlOpen(aabPath, { lazyEntries: true, autoClose: false }, (err, zipfile) => {\n if (err || !zipfile) {\n reject(err ?? new Error(\"Failed to open AAB file\"));\n return;\n }\n\n const entries: ZipEntryInfo[] = [];\n let manifestBuf: Buffer | null = null;\n let rejected = false;\n\n function fail(error: Error): void {\n if (!rejected) {\n rejected = true;\n zipfile.close();\n reject(error);\n }\n }\n\n zipfile.on(\"error\", fail);\n\n zipfile.on(\"entry\", (entry: Entry) => {\n if (rejected) return;\n const path = entry.fileName;\n\n // Collect entry metadata (skip directories)\n if (!path.endsWith(\"/\")) {\n entries.push({\n path,\n compressedSize: entry.compressedSize,\n uncompressedSize: entry.uncompressedSize,\n });\n }\n\n // Extract manifest content\n if (path === MANIFEST_PATH) {\n zipfile.openReadStream(entry, (streamErr, stream) => {\n if (streamErr || !stream) {\n fail(streamErr ?? new Error(\"Failed to read manifest entry\"));\n return;\n }\n\n const chunks: Buffer[] = [];\n stream.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n stream.on(\"error\", (e: Error) => fail(e));\n stream.on(\"end\", () => {\n manifestBuf = Buffer.concat(chunks);\n // Continue to next entry after reading the manifest stream\n zipfile.readEntry();\n });\n });\n } else {\n zipfile.readEntry();\n }\n });\n\n zipfile.on(\"end\", () => {\n if (!rejected) {\n resolve({ zipfile, entries, manifestBuf });\n }\n });\n\n zipfile.readEntry();\n });\n });\n}\n","// Named exports only. No default export.\n\nimport protobuf from \"protobufjs\";\nimport type { ParsedManifest, ManifestComponent, ManifestFeature } from \"./types.js\";\n\n/**\n * Android resource IDs for common manifest attributes.\n * These map protobuf resource_id fields to human-readable names.\n */\nconst RESOURCE_IDS: Record<number, string> = {\n 0x01010000: \"theme\",\n 0x01010001: \"label\",\n 0x01010002: \"icon\",\n 0x01010003: \"name\",\n 0x0101000f: \"versionCode\",\n 0x01010010: \"versionName\",\n 0x0101020c: \"minSdkVersion\",\n 0x01010270: \"targetSdkVersion\",\n 0x0101001e: \"debuggable\",\n 0x01010022: \"permission\",\n 0x0101002b: \"exported\",\n 0x01010272: \"testOnly\",\n 0x010103f0: \"usesCleartextTraffic\",\n 0x010104ea: \"extractNativeLibs\",\n 0x010104d1: \"foregroundServiceType\",\n 0x0101028a: \"required\",\n 0x01010281: \"allowBackup\",\n};\n\n/**\n * Build the AAPT2 XmlNode protobuf schema programmatically.\n * This matches the structure in frameworks/base/tools/aapt2/Resources.proto.\n */\nfunction buildXmlSchema(): protobuf.Root {\n const root = new protobuf.Root();\n const ns = root.define(\"aapt.pb\");\n\n // Source message (line/column info — we skip reading this)\n const Source = new protobuf.Type(\"Source\")\n .add(new protobuf.Field(\"pathIdx\", 1, \"uint32\"))\n .add(new protobuf.Field(\"position\", 2, \"Position\"));\n const Position = new protobuf.Type(\"Position\")\n .add(new protobuf.Field(\"lineNumber\", 1, \"uint32\"))\n .add(new protobuf.Field(\"columnNumber\", 2, \"uint32\"));\n\n // Primitive item — used for compiled attribute values\n const Primitive = new protobuf.Type(\"Primitive\").add(\n new protobuf.OneOf(\"oneofValue\")\n .add(new protobuf.Field(\"intDecimalValue\", 6, \"int32\"))\n .add(new protobuf.Field(\"intHexadecimalValue\", 7, \"uint32\"))\n .add(new protobuf.Field(\"booleanValue\", 8, \"bool\"))\n .add(new protobuf.Field(\"floatValue\", 11, \"float\")),\n );\n\n // Reference — points to another resource\n const Reference = new protobuf.Type(\"Reference\")\n .add(new protobuf.Field(\"id\", 1, \"uint32\"))\n .add(new protobuf.Field(\"name\", 2, \"string\"));\n\n // Item — compiled value of an attribute\n const Item = new protobuf.Type(\"Item\").add(\n new protobuf.OneOf(\"value\")\n .add(new protobuf.Field(\"ref\", 1, \"Reference\"))\n .add(new protobuf.Field(\"str\", 2, \"String\"))\n .add(new protobuf.Field(\"prim\", 4, \"Primitive\")),\n );\n\n const StringMsg = new protobuf.Type(\"String\").add(new protobuf.Field(\"value\", 1, \"string\"));\n\n // XmlAttribute\n const XmlAttribute = new protobuf.Type(\"XmlAttribute\")\n .add(new protobuf.Field(\"namespaceUri\", 1, \"string\"))\n .add(new protobuf.Field(\"name\", 2, \"string\"))\n .add(new protobuf.Field(\"value\", 3, \"string\"))\n .add(new protobuf.Field(\"source\", 4, \"Source\"))\n .add(new protobuf.Field(\"resourceId\", 5, \"uint32\"))\n .add(new protobuf.Field(\"compiledItem\", 6, \"Item\"));\n\n // XmlNamespace\n const XmlNamespace = new protobuf.Type(\"XmlNamespace\")\n .add(new protobuf.Field(\"prefix\", 1, \"string\"))\n .add(new protobuf.Field(\"uri\", 2, \"string\"))\n .add(new protobuf.Field(\"source\", 3, \"Source\"));\n\n // XmlElement\n const XmlElement = new protobuf.Type(\"XmlElement\")\n .add(new protobuf.Field(\"namespaceDeclaration\", 1, \"XmlNamespace\", \"repeated\"))\n .add(new protobuf.Field(\"namespaceUri\", 2, \"string\"))\n .add(new protobuf.Field(\"name\", 3, \"string\"))\n .add(new protobuf.Field(\"attribute\", 4, \"XmlAttribute\", \"repeated\"))\n .add(new protobuf.Field(\"child\", 5, \"XmlNode\", \"repeated\"));\n\n // XmlNode\n const XmlNode = new protobuf.Type(\"XmlNode\")\n .add(\n new protobuf.OneOf(\"node\")\n .add(new protobuf.Field(\"element\", 1, \"XmlElement\"))\n .add(new protobuf.Field(\"text\", 2, \"string\")),\n )\n .add(new protobuf.Field(\"source\", 3, \"Source\"));\n\n ns.add(Position);\n ns.add(Source);\n ns.add(Primitive);\n ns.add(Reference);\n ns.add(StringMsg);\n ns.add(Item);\n ns.add(XmlAttribute);\n ns.add(XmlNamespace);\n ns.add(XmlElement);\n ns.add(XmlNode);\n\n return root;\n}\n\nlet cachedSchema: protobuf.Root | undefined;\n\nfunction getSchema(): protobuf.Root {\n if (!cachedSchema) cachedSchema = buildXmlSchema();\n return cachedSchema;\n}\n\ninterface XmlAttr {\n name: string;\n value: string;\n resourceId: number;\n compiledItem?: {\n prim?: { intDecimalValue?: number; intHexadecimalValue?: number; booleanValue?: boolean };\n str?: { value?: string };\n ref?: { id?: number; name?: string };\n };\n}\n\ninterface XmlElem {\n name: string;\n attribute: XmlAttr[];\n child: XmlNodeParsed[];\n}\n\ninterface XmlNodeParsed {\n element?: XmlElem;\n text?: string;\n}\n\n/** Decode a protobuf-encoded AndroidManifest.xml buffer into a parsed manifest. */\nexport function decodeManifest(buf: Buffer): ParsedManifest {\n const root = getSchema();\n const XmlNode = root.lookupType(\"aapt.pb.XmlNode\");\n const decoded = XmlNode.decode(buf) as unknown as XmlNodeParsed;\n\n if (!decoded.element || decoded.element.name !== \"manifest\") {\n throw new Error(\"Invalid AAB manifest: root element is not <manifest>\");\n }\n\n return extractManifestData(decoded.element);\n}\n\nfunction getAttrValue(attrs: XmlAttr[], resId: number): string | undefined {\n const attr = attrs.find((a) => a.resourceId === resId);\n if (!attr) return undefined;\n // The `value` string field is always populated and is the most reliable source.\n // compiledItem contains structured types but protobuf.js fills default values\n // for all oneof fields, making it unreliable for distinguishing which field is set.\n // Use compiledItem.str for string values (package names, etc.) and fall back to value.\n const ci = attr.compiledItem;\n if (ci?.str?.value !== undefined) return ci.str.value;\n if (ci?.ref?.name !== undefined) return ci.ref.name;\n // For primitives (int, bool), use the string `value` field which is always correct\n return attr.value || undefined;\n}\n\nfunction getAttrByName(attrs: XmlAttr[], name: string): string | undefined {\n const attr = attrs.find((a) => a.name === name || RESOURCE_IDS[a.resourceId] === name);\n if (!attr) return undefined;\n const ci = attr.compiledItem;\n if (ci?.str?.value !== undefined) return ci.str.value;\n if (ci?.ref?.name !== undefined) return ci.ref.name;\n return attr.value || undefined;\n}\n\nfunction getBoolAttr(attrs: XmlAttr[], resId: number, defaultVal: boolean): boolean {\n const val = getAttrValue(attrs, resId);\n if (val === undefined) return defaultVal;\n return val === \"true\" || val === \"1\";\n}\n\nfunction getIntAttr(attrs: XmlAttr[], resId: number, defaultVal: number): number {\n const val = getAttrValue(attrs, resId);\n if (val === undefined) return defaultVal;\n const n = parseInt(val, 10);\n return isNaN(n) ? defaultVal : n;\n}\n\nfunction getChildren(elem: XmlElem, tagName: string): XmlElem[] {\n return (elem.child || [])\n .filter((c): c is XmlNodeParsed & { element: XmlElem } => c.element?.name === tagName)\n .map((c) => c.element);\n}\n\nfunction extractManifestData(manifest: XmlElem): ParsedManifest {\n const attrs = manifest.attribute || [];\n\n const packageName = getAttrByName(attrs, \"package\") || \"\";\n const versionCode = getIntAttr(attrs, 0x0101000f, 0);\n const versionName = getAttrValue(attrs, 0x01010010) || \"\";\n\n // <uses-sdk> element\n const usesSdkElements = getChildren(manifest, \"uses-sdk\");\n const usesSdk = usesSdkElements[0];\n const minSdk = usesSdk ? getIntAttr(usesSdk.attribute || [], 0x0101020c, 1) : 1;\n const targetSdk = usesSdk ? getIntAttr(usesSdk.attribute || [], 0x01010270, minSdk) : minSdk;\n\n // <uses-permission> elements\n const permissions = getChildren(manifest, \"uses-permission\")\n .map((el) => getAttrValue(el.attribute || [], 0x01010003))\n .filter((p): p is string => p !== undefined);\n\n // <uses-feature> elements\n const features: ManifestFeature[] = getChildren(manifest, \"uses-feature\").map((el) => ({\n name: getAttrValue(el.attribute || [], 0x01010003) || \"\",\n required: getBoolAttr(el.attribute || [], 0x0101028a, true),\n }));\n\n // <application> element\n const appElements = getChildren(manifest, \"application\");\n const app = appElements[0];\n\n const debuggable = app ? getBoolAttr(app.attribute || [], 0x0101001e, false) : false;\n const testOnly = getBoolAttr(attrs, 0x01010272, false);\n const usesCleartextTraffic = app ? getBoolAttr(app.attribute || [], 0x010103f0, true) : true;\n const extractNativeLibs = app ? getBoolAttr(app.attribute || [], 0x010104ea, true) : true;\n\n const activities = app ? extractComponents(app, \"activity\") : [];\n const services = app ? extractComponents(app, \"service\") : [];\n const receivers = app ? extractComponents(app, \"receiver\") : [];\n const providers = app ? extractComponents(app, \"provider\") : [];\n\n return {\n packageName,\n versionCode,\n versionName,\n minSdk,\n targetSdk,\n debuggable,\n testOnly,\n usesCleartextTraffic,\n extractNativeLibs,\n permissions,\n features,\n activities,\n services,\n receivers,\n providers,\n };\n}\n\nfunction extractComponents(appElement: XmlElem, tagName: string): ManifestComponent[] {\n return getChildren(appElement, tagName).map((el) => {\n const compAttrs = el.attribute || [];\n const exportedVal = getAttrValue(compAttrs, 0x0101002b);\n const hasIntentFilter = getChildren(el, \"intent-filter\").length > 0;\n\n return {\n name: getAttrValue(compAttrs, 0x01010003) || \"\",\n exported:\n exportedVal === undefined ? undefined : exportedVal === \"true\" || exportedVal === \"1\",\n foregroundServiceType:\n tagName === \"service\" ? getAttrValue(compAttrs, 0x010104d1) : undefined,\n hasIntentFilter,\n };\n });\n}\n","// Named exports only. No default export.\n\nimport type { PreflightScanner, PreflightContext, PreflightFinding } from \"../types.js\";\n\nexport const manifestScanner: PreflightScanner = {\n name: \"manifest\",\n description: \"Checks AndroidManifest.xml for target SDK, debug flags, and component declarations\",\n requires: [\"manifest\"],\n\n async scan(ctx: PreflightContext): Promise<PreflightFinding[]> {\n const manifest = ctx.manifest!;\n const findings: PreflightFinding[] = [];\n const minTargetSdk = ctx.config.targetSdkMinimum;\n\n // targetSdkVersion check\n if (manifest.targetSdk < minTargetSdk) {\n findings.push({\n scanner: \"manifest\",\n ruleId: \"targetSdk-below-minimum\",\n severity: \"critical\",\n title: `targetSdkVersion ${manifest.targetSdk} is below the required ${minTargetSdk}`,\n message: `Google Play requires targetSdkVersion >= ${minTargetSdk} for new apps and updates. Your app targets API ${manifest.targetSdk}.`,\n suggestion: `Update targetSdkVersion to ${minTargetSdk} or higher in your build.gradle file.`,\n policyUrl: \"https://developer.android.com/google/play/requirements/target-sdk\",\n });\n }\n\n // debuggable check\n if (manifest.debuggable) {\n findings.push({\n scanner: \"manifest\",\n ruleId: \"debuggable-true\",\n severity: \"critical\",\n title: \"App is marked as debuggable\",\n message:\n 'android:debuggable=\"true\" is set in the manifest. Google Play rejects debuggable release builds.',\n suggestion:\n \"Remove android:debuggable from your manifest or set it to false. Release builds should never be debuggable.\",\n });\n }\n\n // testOnly check\n if (manifest.testOnly) {\n findings.push({\n scanner: \"manifest\",\n ruleId: \"testOnly-true\",\n severity: \"critical\",\n title: \"App is marked as testOnly\",\n message:\n 'android:testOnly=\"true\" is set in the manifest. Google Play rejects testOnly builds.',\n suggestion:\n \"Remove android:testOnly from your manifest. This flag is only for development builds.\",\n });\n }\n\n // versionCode check\n if (manifest.versionCode <= 0) {\n findings.push({\n scanner: \"manifest\",\n ruleId: \"versionCode-invalid\",\n severity: \"error\",\n title: \"Invalid versionCode\",\n message: `versionCode is ${manifest.versionCode}. It must be a positive integer.`,\n suggestion: \"Set a valid versionCode in your build.gradle file.\",\n });\n }\n\n // cleartext traffic\n if (manifest.usesCleartextTraffic && manifest.targetSdk >= 28) {\n findings.push({\n scanner: \"manifest\",\n ruleId: \"cleartext-traffic\",\n severity: \"warning\",\n title: \"Cleartext HTTP traffic is allowed\",\n message:\n 'android:usesCleartextTraffic=\"true\" allows unencrypted HTTP connections. This is a security risk.',\n suggestion:\n 'Set android:usesCleartextTraffic=\"false\" and use HTTPS. If specific domains need HTTP, use a network security config.',\n policyUrl: \"https://developer.android.com/privacy-and-security/security-config\",\n });\n }\n\n // missing android:exported on components with intent filters (required API 31+)\n if (manifest.targetSdk >= 31) {\n const allComponents = [\n ...manifest.activities,\n ...manifest.services,\n ...manifest.receivers,\n ...manifest.providers,\n ];\n\n for (const comp of allComponents) {\n if (comp.hasIntentFilter && comp.exported === undefined) {\n findings.push({\n scanner: \"manifest\",\n ruleId: \"missing-exported\",\n severity: \"error\",\n title: `Missing android:exported on ${comp.name}`,\n message: `Component \"${comp.name}\" has an intent-filter but no android:exported attribute. This is required for apps targeting API 31+.`,\n suggestion: `Add android:exported=\"true\" or android:exported=\"false\" to the <activity>, <service>, <receiver>, or <provider> declaration for \"${comp.name}\".`,\n policyUrl:\n \"https://developer.android.com/about/versions/12/behavior-changes-12#exported\",\n });\n }\n }\n }\n\n // foreground service type required (API 34+)\n if (manifest.targetSdk >= 34) {\n const hasFgsPerm = manifest.permissions.includes(\"android.permission.FOREGROUND_SERVICE\");\n\n if (hasFgsPerm) {\n for (const service of manifest.services) {\n if (!service.foregroundServiceType) {\n findings.push({\n scanner: \"manifest\",\n ruleId: \"foreground-service-type-missing\",\n severity: \"error\",\n title: `Missing foregroundServiceType on ${service.name}`,\n message: `Service \"${service.name}\" does not declare android:foregroundServiceType. This is required for apps targeting API 34+.`,\n suggestion: `Add android:foregroundServiceType to the <service> declaration. Valid types: camera, connectedDevice, dataSync, health, location, mediaPlayback, mediaProcessing, mediaProjection, microphone, phoneCall, remoteMessaging, shortService, specialUse, systemExempted.`,\n policyUrl:\n \"https://developer.android.com/about/versions/14/changes/fgs-types-required\",\n });\n }\n }\n }\n }\n\n // minSdkVersion advisory\n if (manifest.minSdk < 21) {\n findings.push({\n scanner: \"manifest\",\n ruleId: \"minSdk-below-21\",\n severity: \"info\",\n title: `minSdkVersion ${manifest.minSdk} is very low`,\n message: `minSdkVersion ${manifest.minSdk} means your app supports very old devices (pre-Lollipop). This limits split APK support and modern features.`,\n suggestion:\n \"Consider raising minSdkVersion to 21 or higher to take advantage of modern Android features and better app size optimization.\",\n });\n }\n\n return findings;\n },\n};\n","// Named exports only. No default export.\n\nimport type {\n PreflightScanner,\n PreflightContext,\n PreflightFinding,\n FindingSeverity,\n} from \"../types.js\";\n\ninterface RestrictedPermission {\n permission: string;\n severity: FindingSeverity;\n title: string;\n message: string;\n suggestion: string;\n policyUrl: string;\n}\n\nconst RESTRICTED_PERMISSIONS: RestrictedPermission[] = [\n // SMS permissions — only for default SMS handler\n {\n permission: \"android.permission.READ_SMS\",\n severity: \"critical\",\n title: \"READ_SMS requires declaration form\",\n message:\n \"READ_SMS is restricted to default SMS/phone/assistant handler apps. Google Play requires a Permissions Declaration Form and may reject apps using this permission without approval.\",\n suggestion:\n \"Remove READ_SMS unless your app is a default SMS handler. Use the SMS Retriever API or one-tap SMS consent for OTP verification.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10208820\",\n },\n {\n permission: \"android.permission.SEND_SMS\",\n severity: \"critical\",\n title: \"SEND_SMS requires declaration form\",\n message: \"SEND_SMS is restricted to default SMS handler apps.\",\n suggestion: \"Remove SEND_SMS unless your app is a default SMS handler.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10208820\",\n },\n {\n permission: \"android.permission.RECEIVE_SMS\",\n severity: \"critical\",\n title: \"RECEIVE_SMS requires declaration form\",\n message: \"RECEIVE_SMS is restricted to default SMS handler apps.\",\n suggestion: \"Remove RECEIVE_SMS. Use the SMS Retriever API for OTP verification instead.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10208820\",\n },\n {\n permission: \"android.permission.RECEIVE_MMS\",\n severity: \"critical\",\n title: \"RECEIVE_MMS requires declaration form\",\n message: \"RECEIVE_MMS is restricted to default SMS handler apps.\",\n suggestion: \"Remove RECEIVE_MMS unless your app is a default SMS handler.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10208820\",\n },\n {\n permission: \"android.permission.RECEIVE_WAP_PUSH\",\n severity: \"critical\",\n title: \"RECEIVE_WAP_PUSH requires declaration form\",\n message: \"RECEIVE_WAP_PUSH is restricted to default SMS handler apps.\",\n suggestion: \"Remove RECEIVE_WAP_PUSH unless your app is a default SMS handler.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10208820\",\n },\n // Call log permissions\n {\n permission: \"android.permission.READ_CALL_LOG\",\n severity: \"critical\",\n title: \"READ_CALL_LOG requires declaration form\",\n message: \"READ_CALL_LOG is restricted to default phone/assistant handler apps.\",\n suggestion: \"Remove READ_CALL_LOG unless your app is a default phone or assistant handler.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10208820\",\n },\n {\n permission: \"android.permission.WRITE_CALL_LOG\",\n severity: \"critical\",\n title: \"WRITE_CALL_LOG requires declaration form\",\n message: \"WRITE_CALL_LOG is restricted to default phone handler apps.\",\n suggestion: \"Remove WRITE_CALL_LOG unless your app is a default phone handler.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10208820\",\n },\n {\n permission: \"android.permission.PROCESS_OUTGOING_CALLS\",\n severity: \"critical\",\n title: \"PROCESS_OUTGOING_CALLS requires declaration form\",\n message: \"PROCESS_OUTGOING_CALLS is restricted to default phone handler apps.\",\n suggestion: \"Remove PROCESS_OUTGOING_CALLS unless your app is a default phone handler.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10208820\",\n },\n // Broad visibility\n {\n permission: \"android.permission.QUERY_ALL_PACKAGES\",\n severity: \"error\",\n title: \"QUERY_ALL_PACKAGES requires justification\",\n message:\n \"QUERY_ALL_PACKAGES grants broad package visibility. Google Play requires justification and may reject apps using this without approval.\",\n suggestion:\n \"Replace with targeted <queries> elements in your manifest to declare specific packages you need to interact with.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10158779\",\n },\n // All files access\n {\n permission: \"android.permission.MANAGE_EXTERNAL_STORAGE\",\n severity: \"error\",\n title: \"MANAGE_EXTERNAL_STORAGE (All Files Access) requires declaration form\",\n message:\n \"All Files Access is restricted to file managers, backup apps, antivirus, and document management apps.\",\n suggestion:\n \"Use scoped storage APIs or the Storage Access Framework (SAF) instead. Only use MANAGE_EXTERNAL_STORAGE if your app's core functionality requires broad file access.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10467955\",\n },\n // Background location\n {\n permission: \"android.permission.ACCESS_BACKGROUND_LOCATION\",\n severity: \"error\",\n title: \"ACCESS_BACKGROUND_LOCATION requires declaration and review\",\n message:\n \"Background location access requires a Permissions Declaration Form, privacy policy, and video demonstration. Extended review times apply.\",\n suggestion:\n \"Use foreground location with a foreground service instead. Only use background location if it is essential to your app's core functionality.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/9799150\",\n },\n // Photo/video permissions (May 2025 enforcement)\n {\n permission: \"android.permission.READ_MEDIA_IMAGES\",\n severity: \"error\",\n title: \"READ_MEDIA_IMAGES requires declaration or photo picker\",\n message:\n \"Photo/Video Permissions policy requires either an approved declaration form or use of the Android photo picker for one-time image access.\",\n suggestion:\n \"Use the Android photo picker (ACTION_PICK_IMAGES) for profile pictures and one-time use. Only declare READ_MEDIA_IMAGES if your app's core functionality requires broad gallery access.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/14115180\",\n },\n {\n permission: \"android.permission.READ_MEDIA_VIDEO\",\n severity: \"error\",\n title: \"READ_MEDIA_VIDEO requires declaration or photo picker\",\n message:\n \"Photo/Video Permissions policy requires either an approved declaration form or use of the Android photo picker for one-time video access.\",\n suggestion:\n \"Use the Android photo picker for one-time video selection. Only declare READ_MEDIA_VIDEO if your app's core functionality requires broad video access.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/14115180\",\n },\n // Install packages\n {\n permission: \"android.permission.REQUEST_INSTALL_PACKAGES\",\n severity: \"error\",\n title: \"REQUEST_INSTALL_PACKAGES requires justification\",\n message:\n \"REQUEST_INSTALL_PACKAGES is restricted to apps whose core purpose is installing other packages.\",\n suggestion:\n \"Remove REQUEST_INSTALL_PACKAGES unless your app is an app store, package manager, or OTA updater.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/12085295\",\n },\n // Exact alarm\n {\n permission: \"android.permission.USE_EXACT_ALARM\",\n severity: \"warning\",\n title: \"USE_EXACT_ALARM is restricted\",\n message:\n \"USE_EXACT_ALARM is only for alarm, timer, and calendar apps. Google Play may reject apps using this without justification.\",\n suggestion:\n \"Use SCHEDULE_EXACT_ALARM instead if possible, or remove exact alarm usage if your app does not need precise timing.\",\n policyUrl: \"https://developer.android.com/about/versions/14/changes/schedule-exact-alarms\",\n },\n // Full-screen intent\n {\n permission: \"android.permission.USE_FULL_SCREEN_INTENT\",\n severity: \"warning\",\n title: \"USE_FULL_SCREEN_INTENT requires declaration\",\n message:\n \"Full-screen intents are restricted to alarm and calling apps on Android 14+. A declaration form is required.\",\n suggestion: \"Remove USE_FULL_SCREEN_INTENT unless your app is an alarm clock or calling app.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/13392821\",\n },\n // Accessibility service\n {\n permission: \"android.permission.BIND_ACCESSIBILITY_SERVICE\",\n severity: \"error\",\n title: \"BIND_ACCESSIBILITY_SERVICE requires declaration and justification\",\n message:\n \"Accessibility services must support users with disabilities. A declaration form and detailed justification are required.\",\n suggestion:\n \"Only use BIND_ACCESSIBILITY_SERVICE if your app genuinely assists users with disabilities. Misuse leads to rejection.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10964491\",\n },\n // VPN\n {\n permission: \"android.permission.BIND_VPN_SERVICE\",\n severity: \"error\",\n title: \"BIND_VPN_SERVICE is restricted to VPN apps\",\n message:\n \"BIND_VPN_SERVICE is only for apps whose core functionality is providing VPN services.\",\n suggestion: \"Remove BIND_VPN_SERVICE unless your app is a VPN provider.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/9888170\",\n },\n];\n\n/** Map from permission string to restriction info for fast lookups. */\nconst RESTRICTED_MAP = new Map(RESTRICTED_PERMISSIONS.map((r) => [r.permission, r]));\n\nexport const permissionsScanner: PreflightScanner = {\n name: \"permissions\",\n description: \"Audits declared permissions against Google Play restricted permissions policies\",\n requires: [\"manifest\"],\n\n async scan(ctx: PreflightContext): Promise<PreflightFinding[]> {\n const manifest = ctx.manifest!;\n const findings: PreflightFinding[] = [];\n const allowed = new Set(ctx.config.allowedPermissions);\n\n for (const perm of manifest.permissions) {\n if (allowed.has(perm)) continue;\n\n const restriction = RESTRICTED_MAP.get(perm);\n if (restriction) {\n findings.push({\n scanner: \"permissions\",\n ruleId: `restricted-${perm.split(\".\").pop()?.toLowerCase() || perm}`,\n severity: restriction.severity,\n title: restriction.title,\n message: restriction.message,\n suggestion: restriction.suggestion,\n policyUrl: restriction.policyUrl,\n });\n }\n }\n\n // Data safety reminders for permissions that imply data collection\n const dataPermissions = [\n { perm: \"android.permission.ACCESS_FINE_LOCATION\", data: \"precise location\" },\n { perm: \"android.permission.ACCESS_COARSE_LOCATION\", data: \"approximate location\" },\n { perm: \"android.permission.READ_CONTACTS\", data: \"contacts\" },\n { perm: \"android.permission.CAMERA\", data: \"photos/videos via camera\" },\n { perm: \"android.permission.RECORD_AUDIO\", data: \"audio recordings\" },\n { perm: \"android.permission.READ_CALENDAR\", data: \"calendar events\" },\n { perm: \"android.permission.BODY_SENSORS\", data: \"health/fitness data\" },\n { perm: \"android.permission.ACTIVITY_RECOGNITION\", data: \"physical activity\" },\n ];\n\n const collectedData: string[] = [];\n for (const { perm, data } of dataPermissions) {\n if (manifest.permissions.includes(perm)) {\n collectedData.push(data);\n }\n }\n\n if (collectedData.length > 0) {\n findings.push({\n scanner: \"permissions\",\n ruleId: \"data-safety-reminder\",\n severity: \"info\",\n title: \"Data Safety declaration reminder\",\n message: `Your app declares permissions that imply collecting: ${collectedData.join(\", \")}. Ensure your Data Safety form in Play Console accurately reflects this data collection.`,\n suggestion:\n \"Review your Data Safety declaration at Play Console > Policy > App content > Data safety.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10787469\",\n });\n }\n\n return findings;\n },\n};\n","// Named exports only. No default export.\n\nimport type { PreflightScanner, PreflightContext, PreflightFinding } from \"../types.js\";\n\nconst KNOWN_ABIS = [\"arm64-v8a\", \"armeabi-v7a\", \"x86\", \"x86_64\"] as const;\n\n/** Regex to match native library paths in AAB or APK. */\nconst LIB_PATH_RE = /^(?:[^/]+\\/)?lib\\/([^/]+)\\/[^/]+\\.so$/;\n\nexport const nativeLibsScanner: PreflightScanner = {\n name: \"native-libs\",\n description: \"Checks native library architectures for 64-bit compliance\",\n requires: [\"zipEntries\"],\n\n async scan(ctx: PreflightContext): Promise<PreflightFinding[]> {\n const entries = ctx.zipEntries!;\n const findings: PreflightFinding[] = [];\n\n // Detect which ABIs are present\n const abisFound = new Set<string>();\n let totalNativeSize = 0;\n\n for (const entry of entries) {\n const match = LIB_PATH_RE.exec(entry.path);\n if (match) {\n abisFound.add(match[1]!);\n totalNativeSize += entry.uncompressedSize;\n }\n }\n\n // No native libraries — nothing to check\n if (abisFound.size === 0) {\n return findings;\n }\n\n // 64-bit requirement: if 32-bit ABIs exist, 64-bit counterparts must also exist\n const has32Arm = abisFound.has(\"armeabi-v7a\");\n const has64Arm = abisFound.has(\"arm64-v8a\");\n const has32x86 = abisFound.has(\"x86\");\n const has64x86 = abisFound.has(\"x86_64\");\n\n if (has32Arm && !has64Arm) {\n findings.push({\n scanner: \"native-libs\",\n ruleId: \"missing-arm64\",\n severity: \"critical\",\n title: \"Missing arm64-v8a native libraries\",\n message:\n \"App includes armeabi-v7a (32-bit ARM) native libraries but is missing arm64-v8a (64-bit ARM). Google Play requires 64-bit support for all apps with native code.\",\n suggestion:\n \"Build your native libraries for arm64-v8a. In build.gradle: ndk { abiFilters 'armeabi-v7a', 'arm64-v8a' }\",\n policyUrl: \"https://developer.android.com/google/play/requirements/64-bit\",\n });\n }\n\n if (has32x86 && !has64x86) {\n findings.push({\n scanner: \"native-libs\",\n ruleId: \"missing-x86_64\",\n severity: \"warning\",\n title: \"Missing x86_64 native libraries\",\n message:\n \"App includes x86 (32-bit) native libraries but is missing x86_64 (64-bit). While ARM is required, x86_64 is recommended for emulator and Chromebook support.\",\n suggestion:\n \"Add x86_64 to your ABI filters if you support x86: ndk { abiFilters 'x86', 'x86_64' }\",\n policyUrl: \"https://developer.android.com/google/play/requirements/64-bit\",\n });\n }\n\n // Report detected ABIs\n const detectedAbis = KNOWN_ABIS.filter((abi) => abisFound.has(abi));\n const unknownAbis = [...abisFound].filter(\n (abi) => !(KNOWN_ABIS as readonly string[]).includes(abi),\n );\n\n const abiList = [...detectedAbis, ...unknownAbis].join(\", \");\n const sizeMb = (totalNativeSize / (1024 * 1024)).toFixed(1);\n\n findings.push({\n scanner: \"native-libs\",\n ruleId: \"native-libs-summary\",\n severity: \"info\",\n title: `Native libraries: ${abiList}`,\n message: `Found native libraries for ${abisFound.size} architecture(s): ${abiList}. Total uncompressed size: ${sizeMb} MB.`,\n });\n\n // Warn on large native libraries\n if (totalNativeSize > 150 * 1024 * 1024) {\n findings.push({\n scanner: \"native-libs\",\n ruleId: \"native-libs-large\",\n severity: \"warning\",\n title: \"Large native libraries\",\n message: `Native libraries total ${sizeMb} MB (uncompressed). This significantly increases download size.`,\n suggestion:\n \"Consider using Android App Bundles to deliver only the required ABI per device. Review if all native libraries are necessary.\",\n });\n }\n\n return findings;\n },\n};\n","// Named exports only. No default export.\n\nimport { readdir, stat, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { PreflightScanner, PreflightContext, PreflightFinding } from \"../types.js\";\nimport { lintListing, DEFAULT_LIMITS } from \"../../utils/listing-text.js\";\n\nconst SAFE_LANG = /^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8})*$/;\n\nconst FILE_MAP: Record<string, string> = {\n \"title.txt\": \"title\",\n \"short_description.txt\": \"shortDescription\",\n \"full_description.txt\": \"fullDescription\",\n \"video.txt\": \"video\",\n};\n\nconst SCREENSHOT_DIRS = [\n \"phoneScreenshots\",\n \"sevenInchScreenshots\",\n \"tenInchScreenshots\",\n \"tvScreenshots\",\n \"wearScreenshots\",\n];\n\nconst MIN_PHONE_SCREENSHOTS = 2;\nconst RECOMMENDED_PHONE_SCREENSHOTS = 4;\n\nexport const metadataScanner: PreflightScanner = {\n name: \"metadata\",\n description:\n \"Checks store listing metadata for character limits, required fields, and screenshots\",\n requires: [\"metadataDir\"],\n\n async scan(ctx: PreflightContext): Promise<PreflightFinding[]> {\n const dir = ctx.metadataDir!;\n const findings: PreflightFinding[] = [];\n\n let entries: string[];\n try {\n entries = await readdir(dir);\n } catch {\n findings.push({\n scanner: \"metadata\",\n ruleId: \"metadata-dir-not-found\",\n severity: \"error\",\n title: \"Metadata directory not found\",\n message: `Cannot read metadata directory: ${dir}`,\n suggestion:\n \"Check the path to your metadata directory. Expected Fastlane format: <dir>/<lang>/title.txt, short_description.txt, etc.\",\n });\n return findings;\n }\n\n const locales = entries.filter((e) => SAFE_LANG.test(e));\n if (locales.length === 0) {\n findings.push({\n scanner: \"metadata\",\n ruleId: \"no-locales-found\",\n severity: \"error\",\n title: \"No locale directories found\",\n message: `No valid locale directories found in ${dir}. Expected subdirectories like en-US/, fr-FR/, etc.`,\n suggestion: \"Create locale directories with listing files: <dir>/en-US/title.txt\",\n });\n return findings;\n }\n\n for (const lang of locales) {\n const langDir = join(dir, lang);\n const langStat = await stat(langDir).catch(() => null);\n if (!langStat?.isDirectory()) continue;\n\n // Read listing fields\n const fields: Record<string, string> = {};\n for (const [fileName, field] of Object.entries(FILE_MAP)) {\n const filePath = join(langDir, fileName);\n try {\n const content = await readFile(filePath, \"utf-8\");\n fields[field] = content.trimEnd();\n } catch {\n // File doesn't exist — field is empty\n }\n }\n\n // Lint character limits\n const lintResult = lintListing(lang, fields, DEFAULT_LIMITS);\n for (const field of lintResult.fields) {\n if (field.status === \"over\") {\n findings.push({\n scanner: \"metadata\",\n ruleId: `listing-${field.field}-over-limit`,\n severity: \"error\",\n title: `${lang}: ${field.field} exceeds ${field.limit} character limit`,\n message: `${field.field} is ${field.chars} characters (limit: ${field.limit}). Google Play will reject this listing.`,\n suggestion: `Shorten ${field.field} to ${field.limit} characters or fewer.`,\n });\n } else if (field.status === \"warn\") {\n findings.push({\n scanner: \"metadata\",\n ruleId: `listing-${field.field}-near-limit`,\n severity: \"info\",\n title: `${lang}: ${field.field} is ${field.pct}% of limit`,\n message: `${field.field} is ${field.chars}/${field.limit} characters (${field.pct}%).`,\n });\n }\n }\n\n // Check for missing title\n if (!fields[\"title\"]?.trim()) {\n findings.push({\n scanner: \"metadata\",\n ruleId: \"listing-missing-title\",\n severity: \"error\",\n title: `${lang}: Missing title`,\n message: `No title.txt found or file is empty for locale ${lang}.`,\n suggestion: \"Create a title.txt file with your app name (max 30 characters).\",\n });\n }\n\n // Check screenshot count\n let totalScreenshots = 0;\n let phoneScreenshots = 0;\n\n for (const ssDir of SCREENSHOT_DIRS) {\n const ssPath = join(langDir, \"images\", ssDir);\n try {\n const ssEntries = await readdir(ssPath);\n const imageFiles = ssEntries.filter((f) => /\\.(png|jpe?g|webp)$/i.test(f));\n totalScreenshots += imageFiles.length;\n if (ssDir === \"phoneScreenshots\") {\n phoneScreenshots = imageFiles.length;\n }\n } catch {\n // Screenshot directory doesn't exist\n }\n }\n\n if (phoneScreenshots < MIN_PHONE_SCREENSHOTS && totalScreenshots === 0) {\n findings.push({\n scanner: \"metadata\",\n ruleId: \"listing-no-screenshots\",\n severity: \"warning\",\n title: `${lang}: No screenshots found`,\n message: `No screenshot images found for locale ${lang}. Google Play requires at least 2 phone screenshots.`,\n suggestion: `Add PNG or JPEG screenshots to ${lang}/images/phoneScreenshots/`,\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/9866151\",\n });\n } else if (phoneScreenshots < RECOMMENDED_PHONE_SCREENSHOTS && phoneScreenshots > 0) {\n findings.push({\n scanner: \"metadata\",\n ruleId: \"listing-few-screenshots\",\n severity: \"info\",\n title: `${lang}: Only ${phoneScreenshots} phone screenshot(s)`,\n message: `Found ${phoneScreenshots} phone screenshot(s). Google recommends at least ${RECOMMENDED_PHONE_SCREENSHOTS} for better store presence.`,\n });\n }\n }\n\n // Check for privacy policy URL\n const defaultLang = locales.includes(\"en-US\") ? \"en-US\" : locales[0]!;\n const privacyPath = join(dir, defaultLang, \"privacy_policy_url.txt\");\n try {\n const url = await readFile(privacyPath, \"utf-8\");\n if (!url.trim()) throw new Error(\"empty\");\n } catch {\n findings.push({\n scanner: \"metadata\",\n ruleId: \"listing-no-privacy-policy\",\n severity: \"warning\",\n title: \"No privacy policy URL\",\n message:\n \"No privacy_policy_url.txt found in metadata. A privacy policy is required for most apps on Google Play.\",\n suggestion: `Create ${defaultLang}/privacy_policy_url.txt with a link to your privacy policy.`,\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/9859455\",\n });\n }\n\n // Summary\n findings.push({\n scanner: \"metadata\",\n ruleId: \"metadata-summary\",\n severity: \"info\",\n title: `${locales.length} locale(s) found`,\n message: `Scanned metadata for: ${locales.join(\", \")}`,\n });\n\n return findings;\n },\n};\n","// Named exports only. No default export.\n\nimport { readFile } from \"node:fs/promises\";\nimport type {\n PreflightScanner,\n PreflightContext,\n PreflightFinding,\n FindingSeverity,\n} from \"../types.js\";\nimport { collectSourceFiles } from \"../scan-files.js\";\n\ninterface SecretPattern {\n ruleId: string;\n name: string;\n pattern: RegExp;\n severity: FindingSeverity;\n suggestion: string;\n}\n\nconst SECRET_PATTERNS: SecretPattern[] = [\n {\n ruleId: \"secret-aws-key\",\n name: \"AWS Access Key\",\n pattern: /AKIA[0-9A-Z]{16}/,\n severity: \"critical\",\n suggestion: \"Use environment variables or AWS Secrets Manager. Never hardcode AWS credentials.\",\n },\n {\n ruleId: \"secret-google-api-key\",\n name: \"Google API Key\",\n pattern: /AIza[0-9A-Za-z\\-_]{35}/,\n severity: \"critical\",\n suggestion:\n \"Move Google API keys to local.properties or environment variables. Restrict keys in Google Cloud Console.\",\n },\n {\n ruleId: \"secret-stripe-key\",\n name: \"Stripe Secret Key\",\n pattern: /sk_live_[0-9a-zA-Z]{24,}/,\n severity: \"critical\",\n suggestion:\n \"Never ship Stripe secret keys in client code. Use your backend server for Stripe API calls.\",\n },\n {\n ruleId: \"secret-stripe-restricted\",\n name: \"Stripe Restricted Key\",\n pattern: /rk_live_[0-9a-zA-Z]{24,}/,\n severity: \"critical\",\n suggestion: \"Stripe restricted keys should not be in client code. Use server-side integration.\",\n },\n {\n ruleId: \"secret-private-key\",\n name: \"Private Key\",\n pattern: /-----BEGIN\\s+(RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/,\n severity: \"critical\",\n suggestion:\n \"Remove private keys from source code. Store them in a secure key management system.\",\n },\n {\n ruleId: \"secret-firebase-key\",\n name: \"Firebase API Key in code\",\n pattern: /[\"']AIza[0-9A-Za-z\\-_]{35}[\"']/,\n severity: \"warning\",\n suggestion:\n \"Firebase API keys in client code are normal for google-services.json, but verify they are restricted in Google Cloud Console.\",\n },\n {\n ruleId: \"secret-generic-token\",\n name: \"Generic API Token\",\n pattern:\n /(?:api[_-]?key|api[_-]?secret|auth[_-]?token|access[_-]?token)\\s*[:=]\\s*[\"'][a-zA-Z0-9\\-_]{20,}[\"']/i,\n severity: \"warning\",\n suggestion:\n \"Avoid hardcoding tokens. Use BuildConfig fields, environment variables, or a secrets manager.\",\n },\n];\n\nconst SCAN_EXTENSIONS = new Set([\n \".ts\",\n \".js\",\n \".tsx\",\n \".jsx\",\n \".kt\",\n \".java\",\n \".xml\",\n \".json\",\n \".properties\",\n \".yaml\",\n \".yml\",\n \".gradle\",\n]);\n\nexport const secretsScanner: PreflightScanner = {\n name: \"secrets\",\n description: \"Scans source code for hardcoded credentials and API keys\",\n requires: [\"sourceDir\"],\n\n async scan(ctx: PreflightContext): Promise<PreflightFinding[]> {\n const dir = ctx.sourceDir!;\n const findings: PreflightFinding[] = [];\n const files = await collectSourceFiles(dir, SCAN_EXTENSIONS);\n\n for (const filePath of files) {\n let content: string;\n try {\n content = await readFile(filePath, \"utf-8\");\n } catch {\n continue;\n }\n\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n for (const pattern of SECRET_PATTERNS) {\n if (pattern.pattern.test(line)) {\n const relativePath = filePath.startsWith(dir)\n ? filePath.slice(dir.length + 1)\n : filePath;\n\n findings.push({\n scanner: \"secrets\",\n ruleId: pattern.ruleId,\n severity: pattern.severity,\n title: `${pattern.name} found in ${relativePath}:${i + 1}`,\n message: `Potential ${pattern.name} detected at ${relativePath} line ${i + 1}.`,\n suggestion: pattern.suggestion,\n });\n break; // Only report first match per line\n }\n }\n }\n }\n\n return findings;\n },\n};\n","// Named exports only. No default export.\n\nimport { readdir, stat } from \"node:fs/promises\";\nimport { join, extname } from \"node:path\";\n\nconst DEFAULT_SKIP_DIRS = new Set([\n \".git\",\n \"node_modules\",\n \"build\",\n \"dist\",\n \".gradle\",\n \"__pycache__\",\n \".idea\",\n \".vscode\",\n \"vendor\",\n]);\n\n/**\n * Recursively collect files matching the given extensions.\n * Skips common non-source directories (node_modules, build, .git, etc.).\n */\nexport async function collectSourceFiles(\n dir: string,\n extensions: Set<string>,\n skipDirs: Set<string> = DEFAULT_SKIP_DIRS,\n maxDepth: number = 10,\n): Promise<string[]> {\n if (maxDepth <= 0) return [];\n const files: string[] = [];\n\n let entries: string[];\n try {\n entries = await readdir(dir);\n } catch {\n return files;\n }\n\n for (const entry of entries) {\n if (skipDirs.has(entry)) continue;\n\n const fullPath = join(dir, entry);\n const s = await stat(fullPath).catch(() => null);\n if (!s) continue;\n\n if (s.isDirectory()) {\n const sub = await collectSourceFiles(fullPath, extensions, skipDirs, maxDepth - 1);\n files.push(...sub);\n } else if (s.isFile()) {\n const ext = extname(entry).toLowerCase();\n // Also match compound extensions like .gradle.kts\n if (extensions.has(ext) || entry.endsWith(\".gradle.kts\")) {\n files.push(fullPath);\n }\n }\n }\n\n return files;\n}\n","// Named exports only. No default export.\n\nimport { readFile } from \"node:fs/promises\";\nimport type { PreflightScanner, PreflightContext, PreflightFinding } from \"../types.js\";\nimport { collectSourceFiles } from \"../scan-files.js\";\n\ninterface BillingPattern {\n ruleId: string;\n name: string;\n pattern: RegExp;\n message: string;\n suggestion: string;\n}\n\nconst BILLING_PATTERNS: BillingPattern[] = [\n {\n ruleId: \"billing-stripe-sdk\",\n name: \"Stripe SDK\",\n pattern: /(?:com\\.stripe|@stripe\\/|stripe-android|StripeSdk)/,\n message:\n \"Stripe SDK detected. Google Play requires Play Billing for in-app purchases of digital goods.\",\n suggestion:\n \"If selling digital goods, use Google Play Billing Library. Stripe is only allowed for physical goods, services, or out-of-app purchases.\",\n },\n {\n ruleId: \"billing-braintree-sdk\",\n name: \"Braintree SDK\",\n pattern: /(?:com\\.braintreepayments|braintree-android)/,\n message:\n \"Braintree SDK detected. Google Play requires Play Billing for digital in-app purchases.\",\n suggestion:\n \"Use Google Play Billing Library for digital goods. Braintree is only allowed for physical goods and services.\",\n },\n {\n ruleId: \"billing-paypal-sdk\",\n name: \"PayPal SDK\",\n pattern: /(?:com\\.paypal|paypal-android)/,\n message: \"PayPal SDK detected. Google Play requires Play Billing for digital in-app purchases.\",\n suggestion:\n \"Use Google Play Billing Library for digital goods. PayPal is allowed for physical goods only.\",\n },\n {\n ruleId: \"billing-razorpay-sdk\",\n name: \"Razorpay SDK\",\n pattern: /(?:com\\.razorpay)/,\n message:\n \"Razorpay SDK detected. If used for digital goods, this may violate Google Play billing policy.\",\n suggestion:\n \"Ensure Razorpay is only used for physical goods/services. Digital goods require Play Billing.\",\n },\n {\n ruleId: \"billing-checkout-sdk\",\n name: \"Alternative checkout SDK\",\n pattern: /(?:com\\.adyen|com\\.checkout|com\\.square\\.sdk)/,\n message:\n \"Alternative payment SDK detected. Google Play requires Play Billing for digital goods.\",\n suggestion:\n \"Verify this payment SDK is only used for physical goods or services, not digital content.\",\n },\n];\n\nconst SCAN_EXTENSIONS = new Set([\n \".kt\",\n \".java\",\n \".xml\",\n \".gradle\",\n \".ts\",\n \".js\",\n \".tsx\",\n \".jsx\",\n \".json\",\n]);\n\nexport const billingScanner: PreflightScanner = {\n name: \"billing\",\n description: \"Detects non-Play billing SDKs that may violate Google Play billing policy\",\n requires: [\"sourceDir\"],\n\n async scan(ctx: PreflightContext): Promise<PreflightFinding[]> {\n const dir = ctx.sourceDir!;\n const findings: PreflightFinding[] = [];\n const detectedSdks = new Set<string>();\n const files = await collectSourceFiles(dir, SCAN_EXTENSIONS);\n\n for (const filePath of files) {\n let content: string;\n try {\n content = await readFile(filePath, \"utf-8\");\n } catch {\n continue;\n }\n\n for (const bp of BILLING_PATTERNS) {\n if (detectedSdks.has(bp.ruleId)) continue; // Only report each SDK once\n\n if (bp.pattern.test(content)) {\n const relativePath = filePath.startsWith(dir) ? filePath.slice(dir.length + 1) : filePath;\n\n detectedSdks.add(bp.ruleId);\n findings.push({\n scanner: \"billing\",\n ruleId: bp.ruleId,\n severity: \"warning\",\n title: `${bp.name} detected`,\n message: `${bp.message} Found in ${relativePath}.`,\n suggestion: bp.suggestion,\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10281818\",\n });\n }\n }\n }\n\n return findings;\n },\n};\n","// Named exports only. No default export.\n\nimport { readFile } from \"node:fs/promises\";\nimport type { PreflightScanner, PreflightContext, PreflightFinding } from \"../types.js\";\nimport { collectSourceFiles } from \"../scan-files.js\";\n\ninterface TrackingSdk {\n name: string;\n pattern: RegExp;\n}\n\nconst TRACKING_SDKS: TrackingSdk[] = [\n {\n name: \"Facebook SDK\",\n pattern: /(?:com\\.facebook\\.sdk|com\\.facebook\\.android|FacebookSdk\\.sdkInitialize)/i,\n },\n { name: \"Adjust SDK\", pattern: /(?:com\\.adjust\\.sdk|AdjustConfig|AdjustEvent)/i },\n {\n name: \"AppsFlyer SDK\",\n pattern: /(?:com\\.appsflyer|AppsFlyerLib|AppsFlyerConversionListener)/i,\n },\n { name: \"Amplitude SDK\", pattern: /(?:com\\.amplitude|AmplitudeClient|@amplitude\\/analytics)/i },\n { name: \"Mixpanel SDK\", pattern: /(?:com\\.mixpanel|MixpanelAPI|@mixpanel)/i },\n { name: \"Branch SDK\", pattern: /(?:io\\.branch\\.referral|Branch\\.getInstance)/i },\n { name: \"CleverTap SDK\", pattern: /(?:com\\.clevertap|CleverTapAPI)/i },\n { name: \"Singular SDK\", pattern: /(?:com\\.singular\\.sdk|SingularConfig)/i },\n];\n\nconst SCAN_EXTENSIONS = new Set([\n \".kt\",\n \".java\",\n \".xml\",\n \".gradle\",\n \".ts\",\n \".js\",\n \".tsx\",\n \".jsx\",\n \".json\",\n]);\n\nexport const privacyScanner: PreflightScanner = {\n name: \"privacy\",\n description: \"Detects tracking SDKs and data collection patterns for Data Safety compliance\",\n requires: [\"sourceDir\"],\n\n async scan(ctx: PreflightContext): Promise<PreflightFinding[]> {\n const dir = ctx.sourceDir!;\n const findings: PreflightFinding[] = [];\n const detectedSdks = new Set<string>();\n const files = await collectSourceFiles(dir, SCAN_EXTENSIONS);\n\n for (const filePath of files) {\n let content: string;\n try {\n content = await readFile(filePath, \"utf-8\");\n } catch {\n continue;\n }\n\n // Check for tracking SDKs\n for (const sdk of TRACKING_SDKS) {\n if (detectedSdks.has(sdk.name)) continue;\n\n if (sdk.pattern.test(content)) {\n detectedSdks.add(sdk.name);\n const relativePath = filePath.startsWith(dir) ? filePath.slice(dir.length + 1) : filePath;\n\n findings.push({\n scanner: \"privacy\",\n ruleId: `tracking-${sdk.name.toLowerCase().replace(/\\s+/g, \"-\")}`,\n severity: \"warning\",\n title: `${sdk.name} detected`,\n message: `${sdk.name} found in ${relativePath}. This SDK typically collects analytics or attribution data that must be declared in your Data Safety form.`,\n suggestion:\n \"Ensure your Data Safety declaration accurately lists all data types collected by this SDK.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10787469\",\n });\n }\n }\n\n // Check for ADVERTISING_ID\n if (\n content.includes(\"AD_ID\") ||\n content.includes(\"ADVERTISING_ID\") ||\n content.includes(\"AdvertisingIdClient\")\n ) {\n if (!detectedSdks.has(\"_ad_id\")) {\n detectedSdks.add(\"_ad_id\");\n findings.push({\n scanner: \"privacy\",\n ruleId: \"advertising-id-usage\",\n severity: \"warning\",\n title: \"Advertising ID usage detected\",\n message:\n \"Your app appears to access the Advertising ID. This must be declared in your Data Safety form under 'Device or other IDs'.\",\n suggestion:\n \"Declare Advertising ID collection in Play Console > Data safety. If your app targets children, Advertising ID usage is restricted.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/11043825\",\n });\n }\n }\n }\n\n // Cross-reference with manifest permissions if available\n if (ctx.manifest) {\n const dataPermissions: Array<{ perm: string; dataType: string }> = [\n { perm: \"android.permission.ACCESS_FINE_LOCATION\", dataType: \"precise location\" },\n { perm: \"android.permission.ACCESS_COARSE_LOCATION\", dataType: \"approximate location\" },\n { perm: \"android.permission.READ_CONTACTS\", dataType: \"contacts\" },\n { perm: \"android.permission.CAMERA\", dataType: \"photos/videos\" },\n { perm: \"android.permission.RECORD_AUDIO\", dataType: \"audio\" },\n { perm: \"android.permission.READ_CALENDAR\", dataType: \"calendar\" },\n { perm: \"android.permission.BODY_SENSORS\", dataType: \"health/fitness data\" },\n { perm: \"android.permission.READ_PHONE_STATE\", dataType: \"phone state/device ID\" },\n ];\n\n const collectedTypes: string[] = [];\n for (const { perm, dataType } of dataPermissions) {\n if (ctx.manifest.permissions.includes(perm)) {\n collectedTypes.push(dataType);\n }\n }\n\n if (collectedTypes.length > 0 && detectedSdks.size > 0) {\n findings.push({\n scanner: \"privacy\",\n ruleId: \"data-collection-cross-reference\",\n severity: \"info\",\n title: \"Data collection cross-reference\",\n message: `Your app requests permissions for: ${collectedTypes.join(\", \")}. Combined with ${detectedSdks.size} tracking SDK(s), ensure your Data Safety form declares all collected data types.`,\n suggestion:\n \"Review your Data Safety form at Play Console > Policy > App content > Data safety.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10787469\",\n });\n }\n }\n\n return findings;\n },\n};\n","// Named exports only. No default export.\n\nimport type { PreflightScanner, PreflightContext, PreflightFinding } from \"../types.js\";\n\n/** Heuristic policy checks based on manifest permissions and features. */\nexport const policyScanner: PreflightScanner = {\n name: \"policy\",\n description:\n \"Heuristic checks for Google Play policy compliance (families, financial, health, gambling)\",\n requires: [\"manifest\"],\n\n async scan(ctx: PreflightContext): Promise<PreflightFinding[]> {\n const manifest = ctx.manifest!;\n const findings: PreflightFinding[] = [];\n const perms = new Set(manifest.permissions);\n\n // Families / COPPA indicators\n if (manifest.targetSdk >= 28) {\n const childrenIndicators = [\n perms.has(\"android.permission.READ_CONTACTS\"),\n perms.has(\"android.permission.ACCESS_FINE_LOCATION\"),\n perms.has(\"android.permission.RECORD_AUDIO\"),\n ];\n const hasChildFeatures = manifest.features.some(\n (f) =>\n f.name.includes(\"kids\") || f.name.includes(\"children\") || f.name.includes(\"education\"),\n );\n\n if (hasChildFeatures && childrenIndicators.some(Boolean)) {\n findings.push({\n scanner: \"policy\",\n ruleId: \"policy-families-data-collection\",\n severity: \"warning\",\n title: \"Potential Families Policy concern\",\n message:\n \"App appears to target children (based on features) but requests sensitive permissions (location, contacts, or audio). Apps in the Families program have strict data collection limits.\",\n suggestion:\n \"Review the Families Policy requirements. Apps for children must minimize data collection and cannot use advertising ID.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/9893335\",\n });\n }\n }\n\n // Financial app indicators\n const financialPerms = [\n perms.has(\"android.permission.READ_SMS\"),\n perms.has(\"android.permission.RECEIVE_SMS\"),\n perms.has(\"android.permission.BIND_AUTOFILL_SERVICE\"),\n ];\n if (financialPerms.filter(Boolean).length >= 2) {\n findings.push({\n scanner: \"policy\",\n ruleId: \"policy-financial-app\",\n severity: \"warning\",\n title: \"Potential financial app detected\",\n message:\n \"App requests SMS + autofill permissions, common in financial apps. Financial apps must comply with additional disclosure and security requirements.\",\n suggestion:\n \"Ensure your app meets Google Play's financial services policy. Declare appropriate app category in Play Console.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/9876821\",\n });\n }\n\n // Health app indicators\n if (\n perms.has(\"android.permission.BODY_SENSORS\") ||\n perms.has(\"android.permission.ACTIVITY_RECOGNITION\")\n ) {\n findings.push({\n scanner: \"policy\",\n ruleId: \"policy-health-app\",\n severity: \"info\",\n title: \"Health/fitness app detected\",\n message:\n \"App requests body sensor or activity recognition permissions. Health apps must comply with health data policies.\",\n suggestion:\n \"Review Google Play's health app policy. Ensure accurate health claims and proper data handling disclosures.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10787469\",\n });\n }\n\n // UGC indicators\n const ugcIndicators = [\n perms.has(\"android.permission.CAMERA\"),\n perms.has(\"android.permission.RECORD_AUDIO\"),\n perms.has(\"android.permission.READ_MEDIA_IMAGES\"),\n ];\n if (ugcIndicators.filter(Boolean).length >= 2) {\n findings.push({\n scanner: \"policy\",\n ruleId: \"policy-ugc-content\",\n severity: \"info\",\n title: \"User-generated content indicators\",\n message:\n \"App requests camera + audio/media permissions, suggesting user-generated content. Apps with UGC must have content moderation.\",\n suggestion:\n \"Implement content moderation, reporting mechanisms, and content policies if your app allows user-generated content.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/9876937\",\n });\n }\n\n // System alert window / overlay\n if (perms.has(\"android.permission.SYSTEM_ALERT_WINDOW\")) {\n findings.push({\n scanner: \"policy\",\n ruleId: \"policy-overlay\",\n severity: \"warning\",\n title: \"SYSTEM_ALERT_WINDOW (overlay) permission\",\n message:\n \"App requests overlay permission. This is restricted and must be justified. Misuse can lead to rejection.\",\n suggestion:\n \"Only use SYSTEM_ALERT_WINDOW if overlay display is core to your app's functionality.\",\n });\n }\n\n return findings;\n },\n};\n","// Named exports only. No default export.\n\nimport type { PreflightScanner, PreflightContext, PreflightFinding } from \"../types.js\";\n\nexport const sizeScanner: PreflightScanner = {\n name: \"size\",\n description: \"Analyzes app bundle size and warns on large downloads\",\n requires: [\"zipEntries\"],\n\n async scan(ctx: PreflightContext): Promise<PreflightFinding[]> {\n const entries = ctx.zipEntries!;\n const findings: PreflightFinding[] = [];\n const maxMb = ctx.config.maxDownloadSizeMb;\n\n // Total compressed size (approximate download size)\n const totalCompressed = entries.reduce((sum, e) => sum + e.compressedSize, 0);\n const totalUncompressed = entries.reduce((sum, e) => sum + e.uncompressedSize, 0);\n const compressedMb = totalCompressed / (1024 * 1024);\n const uncompressedMb = totalUncompressed / (1024 * 1024);\n\n if (compressedMb > maxMb) {\n findings.push({\n scanner: \"size\",\n ruleId: \"size-over-limit\",\n severity: \"warning\",\n title: `Download size exceeds ${maxMb} MB`,\n message: `Compressed size is ${compressedMb.toFixed(1)} MB. Downloads over ${maxMb} MB show a mobile data warning to users, which reduces install rates.`,\n suggestion:\n \"Use Android App Bundles for split APKs, remove unused resources, enable R8/ProGuard, and compress assets.\",\n policyUrl: \"https://developer.android.com/topic/performance/reduce-apk-size\",\n });\n }\n\n // Per-category breakdown\n const categories = new Map<\n string,\n { compressed: number; uncompressed: number; count: number }\n >();\n for (const entry of entries) {\n const cat = detectCategory(entry.path);\n const existing = categories.get(cat) ?? { compressed: 0, uncompressed: 0, count: 0 };\n existing.compressed += entry.compressedSize;\n existing.uncompressed += entry.uncompressedSize;\n existing.count += 1;\n categories.set(cat, existing);\n }\n\n // Large native libs\n const nativeLibs = categories.get(\"native-libs\");\n if (nativeLibs && nativeLibs.compressed > 50 * 1024 * 1024) {\n findings.push({\n scanner: \"size\",\n ruleId: \"size-large-native\",\n severity: \"warning\",\n title: \"Large native libraries\",\n message: `Native libraries are ${(nativeLibs.compressed / (1024 * 1024)).toFixed(1)} MB (compressed). This is the largest contributor to download size.`,\n suggestion:\n \"Review which native libraries are bundled. Consider using dynamic feature modules for optional native code.\",\n });\n }\n\n // Large assets\n const assets = categories.get(\"assets\");\n if (assets && assets.compressed > 30 * 1024 * 1024) {\n findings.push({\n scanner: \"size\",\n ruleId: \"size-large-assets\",\n severity: \"info\",\n title: \"Large assets directory\",\n message: `Assets are ${(assets.compressed / (1024 * 1024)).toFixed(1)} MB (compressed). Consider using Play Asset Delivery for large assets.`,\n suggestion:\n \"Move large assets to Play Asset Delivery (install-time, fast-follow, or on-demand packs).\",\n policyUrl: \"https://developer.android.com/guide/playcore/asset-delivery\",\n });\n }\n\n // Summary\n const breakdown = [...categories.entries()]\n .sort((a, b) => b[1].compressed - a[1].compressed)\n .map(([cat, data]) => `${cat}: ${(data.compressed / (1024 * 1024)).toFixed(1)} MB`)\n .join(\", \");\n\n findings.push({\n scanner: \"size\",\n ruleId: \"size-summary\",\n severity: \"info\",\n title: `Total size: ${compressedMb.toFixed(1)} MB compressed, ${uncompressedMb.toFixed(1)} MB uncompressed`,\n message: `${entries.length} files. Breakdown: ${breakdown}`,\n });\n\n return findings;\n },\n};\n\nfunction detectCategory(path: string): string {\n const lower = path.toLowerCase();\n if (lower.endsWith(\".dex\") || /\\/dex\\//.test(lower)) return \"dex\";\n if (/\\/lib\\/[^/]+\\/[^/]+\\.so$/.test(lower)) return \"native-libs\";\n if (/\\/res\\//.test(lower) || lower.endsWith(\"/resources.pb\") || lower.endsWith(\"/resources.arsc\"))\n return \"resources\";\n if (/\\/assets\\//.test(lower)) return \"assets\";\n if (lower.includes(\"androidmanifest.xml\") || /\\/manifest\\//.test(lower)) return \"manifest\";\n if (lower.startsWith(\"meta-inf/\")) return \"signing\";\n return \"other\";\n}\n","// Named exports only. No default export.\n\nimport type {\n PreflightOptions,\n PreflightResult,\n PreflightContext,\n PreflightScanner,\n PreflightFinding,\n FindingSeverity,\n} from \"./types.js\";\nimport { SEVERITY_ORDER, DEFAULT_PREFLIGHT_CONFIG } from \"./types.js\";\nimport { loadPreflightConfig } from \"./config.js\";\nimport { readAab } from \"./aab-reader.js\";\nimport { manifestScanner } from \"./scanners/manifest-scanner.js\";\nimport { permissionsScanner } from \"./scanners/permissions-scanner.js\";\nimport { nativeLibsScanner } from \"./scanners/native-libs-scanner.js\";\nimport { metadataScanner } from \"./scanners/metadata-scanner.js\";\nimport { secretsScanner } from \"./scanners/secrets-scanner.js\";\nimport { billingScanner } from \"./scanners/billing-scanner.js\";\nimport { privacyScanner } from \"./scanners/privacy-scanner.js\";\nimport { policyScanner } from \"./scanners/policy-scanner.js\";\nimport { sizeScanner } from \"./scanners/size-scanner.js\";\n\n/** All registered scanners. New scanners are added here. */\nconst ALL_SCANNERS: PreflightScanner[] = [\n manifestScanner,\n permissionsScanner,\n nativeLibsScanner,\n metadataScanner,\n secretsScanner,\n billingScanner,\n privacyScanner,\n policyScanner,\n sizeScanner,\n];\n\nexport function getAllScannerNames(): string[] {\n return ALL_SCANNERS.map((s) => s.name);\n}\n\nexport async function runPreflight(options: PreflightOptions): Promise<PreflightResult> {\n const start = Date.now();\n\n // Load config (file + CLI overrides)\n const fileConfig = await loadPreflightConfig(options.configPath);\n const config = {\n ...fileConfig,\n failOn: options.failOn ?? fileConfig.failOn ?? DEFAULT_PREFLIGHT_CONFIG.failOn,\n };\n\n // Build context\n const ctx: PreflightContext = { config };\n\n // Open AAB if provided\n const earlyFindings: PreflightFinding[] = [];\n if (options.aabPath) {\n ctx.aabPath = options.aabPath;\n const aab = await readAab(options.aabPath);\n ctx.manifest = aab.manifest;\n ctx.zipEntries = aab.entries;\n\n // If manifest had a parse error, emit a warning and clear manifest\n // so manifest-dependent scanners are skipped gracefully\n if (aab.manifest._parseError) {\n earlyFindings.push({\n scanner: \"manifest-parser\",\n ruleId: \"manifest-parse-error\",\n severity: \"warning\",\n title: \"Manifest could not be fully parsed\",\n message: aab.manifest._parseError,\n suggestion: \"Manifest-dependent scanners (manifest, permissions, policy, privacy) were skipped. Other scanners (native-libs, size, secrets, billing) still ran.\",\n });\n ctx.manifest = undefined;\n }\n }\n\n if (options.metadataDir) ctx.metadataDir = options.metadataDir;\n if (options.sourceDir) ctx.sourceDir = options.sourceDir;\n\n // Filter scanners\n const requestedNames = options.scanners\n ? new Set(options.scanners.map((s) => s.toLowerCase()))\n : null;\n\n const applicableScanners = ALL_SCANNERS.filter((scanner) => {\n // Filter by name if specified\n if (requestedNames && !requestedNames.has(scanner.name)) return false;\n\n // Filter by context availability\n for (const req of scanner.requires) {\n if (req === \"manifest\" && !ctx.manifest) return false;\n if (req === \"zipEntries\" && !ctx.zipEntries) return false;\n if (req === \"metadataDir\" && !ctx.metadataDir) return false;\n if (req === \"sourceDir\" && !ctx.sourceDir) return false;\n }\n\n return true;\n });\n\n // Run all applicable scanners in parallel — use allSettled so one failure doesn't stop others\n const settled = await Promise.allSettled(applicableScanners.map((scanner) => scanner.scan(ctx)));\n\n // Flatten findings, report scanner failures as error findings\n let findings: PreflightFinding[] = [...earlyFindings];\n for (let i = 0; i < settled.length; i++) {\n const result = settled[i]!;\n if (result.status === \"fulfilled\") {\n findings.push(...result.value);\n } else {\n const scanner = applicableScanners[i]!;\n findings.push({\n scanner: scanner.name,\n ruleId: \"scanner-error\",\n severity: \"error\",\n title: `Scanner \"${scanner.name}\" failed`,\n message: result.reason instanceof Error ? result.reason.message : String(result.reason),\n suggestion: \"This scanner encountered an unexpected error. Other scanners still ran.\",\n });\n }\n }\n\n // Apply disabled rules\n if (config.disabledRules.length > 0) {\n const disabled = new Set(config.disabledRules);\n findings = findings.filter((f) => !disabled.has(f.ruleId));\n }\n\n // Apply severity overrides\n if (Object.keys(config.severityOverrides).length > 0) {\n findings = findings.map((f) => {\n const override = config.severityOverrides[f.ruleId];\n return override ? { ...f, severity: override } : f;\n });\n }\n\n // Sort by severity (critical first)\n findings.sort((a, b) => SEVERITY_ORDER[b.severity] - SEVERITY_ORDER[a.severity]);\n\n // Compute summary\n const summary: Record<FindingSeverity, number> = { critical: 0, error: 0, warning: 0, info: 0 };\n for (const f of findings) summary[f.severity]++;\n\n // Check pass/fail threshold\n const failThreshold = SEVERITY_ORDER[config.failOn];\n const passed = !findings.some((f) => SEVERITY_ORDER[f.severity] >= failThreshold);\n\n return {\n scanners: applicableScanners.map((s) => s.name),\n findings,\n summary,\n passed,\n durationMs: Date.now() - start,\n };\n}\n","/**\n * Sort utility for CLI list command results.\n *\n * Supports ascending (field) and descending (-field) sort specs,\n * including dot notation for nested fields (e.g., \"comments.userComment.starRating\").\n */\n\nfunction getNestedValue(obj: unknown, path: string): unknown {\n const parts = path.split(\".\");\n let current: unknown = obj;\n for (const part of parts) {\n if (current === null || current === undefined || typeof current !== \"object\") {\n return undefined;\n }\n current = (current as Record<string, unknown>)[part];\n }\n return current;\n}\n\nfunction compare(a: unknown, b: unknown): number {\n if (a === undefined && b === undefined) return 0;\n if (a === undefined) return 1;\n if (b === undefined) return -1;\n\n if (typeof a === \"number\" && typeof b === \"number\") {\n return a - b;\n }\n\n return String(a).localeCompare(String(b));\n}\n\n/**\n * Sort an array of items by a field specification.\n *\n * @param items - Array to sort (not mutated; returns a new array)\n * @param sortSpec - Field name for ascending, or `-field` for descending.\n * Supports dot notation for nested fields.\n * If undefined/empty, returns items in original order.\n * @returns Sorted copy of items\n */\nexport function sortResults<T>(items: T[], sortSpec?: string): T[] {\n if (!sortSpec || items.length === 0) {\n return items;\n }\n\n const descending = sortSpec.startsWith(\"-\");\n const field = descending ? sortSpec.slice(1) : sortSpec;\n\n // Validate that at least one item has the field — if none do, return original order\n const hasField = items.some((item) => getNestedValue(item, field) !== undefined);\n if (!hasField) {\n return items;\n }\n\n const sorted = [...items].sort((a, b) => {\n const aVal = getNestedValue(a, field);\n const bVal = getNestedValue(b, field);\n const result = compare(aVal, bVal);\n return descending ? -result : result;\n });\n\n return sorted;\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport interface ScaffoldOptions {\n name: string;\n dir: string;\n description?: string;\n}\n\nexport interface ScaffoldResult {\n dir: string;\n files: string[];\n}\n\n/**\n * Scaffold a new GPC plugin project.\n */\nexport async function scaffoldPlugin(options: ScaffoldOptions): Promise<ScaffoldResult> {\n const { name, dir, description = `GPC plugin: ${name}` } = options;\n\n // Ensure name follows convention\n const pluginName = name.startsWith(\"gpc-plugin-\") ? name : `gpc-plugin-${name}`;\n const shortName = pluginName.replace(/^gpc-plugin-/, \"\");\n\n const srcDir = join(dir, \"src\");\n const testDir = join(dir, \"tests\");\n\n await mkdir(srcDir, { recursive: true });\n await mkdir(testDir, { recursive: true });\n\n const files: string[] = [];\n\n // package.json\n const pkg = {\n name: pluginName,\n version: \"0.1.0\",\n description,\n type: \"module\",\n main: \"./dist/index.js\",\n types: \"./dist/index.d.ts\",\n exports: {\n \".\": {\n import: \"./dist/index.js\",\n types: \"./dist/index.d.ts\",\n },\n },\n files: [\"dist\"],\n scripts: {\n build: \"tsup src/index.ts --format esm --dts\",\n dev: \"tsup src/index.ts --format esm --dts --watch\",\n test: \"vitest run\",\n \"test:watch\": \"vitest\",\n },\n keywords: [\"gpc\", \"gpc-plugin\", \"google-play\"],\n license: \"MIT\",\n peerDependencies: {\n \"@gpc-cli/plugin-sdk\": \">=0.8.0\",\n },\n devDependencies: {\n \"@gpc-cli/plugin-sdk\": \"^0.8.0\",\n tsup: \"^8.0.0\",\n typescript: \"^5.0.0\",\n vitest: \"^3.0.0\",\n },\n };\n await writeFile(join(dir, \"package.json\"), JSON.stringify(pkg, null, 2) + \"\\n\");\n files.push(\"package.json\");\n\n // tsconfig.json\n const tsconfig = {\n compilerOptions: {\n target: \"ES2022\",\n module: \"ESNext\",\n moduleResolution: \"bundler\",\n declaration: true,\n strict: true,\n esModuleInterop: true,\n skipLibCheck: true,\n outDir: \"./dist\",\n rootDir: \"./src\",\n },\n include: [\"src\"],\n };\n await writeFile(join(dir, \"tsconfig.json\"), JSON.stringify(tsconfig, null, 2) + \"\\n\");\n files.push(\"tsconfig.json\");\n\n // src/index.ts\n const srcContent = `import { definePlugin } from \"@gpc-cli/plugin-sdk\";\nimport type { CommandEvent, CommandResult } from \"@gpc-cli/plugin-sdk\";\n\nexport const plugin = definePlugin({\n name: \"${pluginName}\",\n version: \"0.1.0\",\n\n register(hooks) {\n hooks.beforeCommand(async (event: CommandEvent) => {\n // Called before every gpc command\n // Example: log command usage, validate prerequisites, etc.\n });\n\n hooks.afterCommand(async (event: CommandEvent, result: CommandResult) => {\n // Called after every successful gpc command\n // Example: send notifications, update dashboards, etc.\n });\n\n // Uncomment to add custom commands:\n // hooks.registerCommands((registry) => {\n // registry.add({\n // name: \"${shortName}\",\n // description: \"${description}\",\n // action: async (args, opts) => {\n // console.log(\"Hello from ${pluginName}!\");\n // },\n // });\n // });\n },\n});\n`;\n await writeFile(join(srcDir, \"index.ts\"), srcContent);\n files.push(\"src/index.ts\");\n\n // tests/plugin.test.ts\n const testContent = `import { describe, it, expect, vi } from \"vitest\";\nimport { plugin } from \"../src/index\";\n\ndescribe(\"${pluginName}\", () => {\n it(\"has correct name and version\", () => {\n expect(plugin.name).toBe(\"${pluginName}\");\n expect(plugin.version).toBe(\"0.1.0\");\n });\n\n it(\"registers without errors\", () => {\n const hooks = {\n beforeCommand: vi.fn(),\n afterCommand: vi.fn(),\n onError: vi.fn(),\n beforeRequest: vi.fn(),\n afterResponse: vi.fn(),\n registerCommands: vi.fn(),\n };\n\n expect(() => plugin.register(hooks)).not.toThrow();\n });\n});\n`;\n await writeFile(join(testDir, \"plugin.test.ts\"), testContent);\n files.push(\"tests/plugin.test.ts\");\n\n return { dir, files };\n}\n","import type { WebhookConfig } from \"@gpc-cli/config\";\n\nexport interface WebhookPayload {\n command: string;\n success: boolean;\n duration: number;\n app?: string;\n details?: Record<string, unknown>;\n error?: string;\n}\n\nexport function formatSlackPayload(payload: WebhookPayload): object {\n const status = payload.success ? \"\\u2713\" : \"\\u2717\";\n const color = payload.success ? \"#2eb886\" : \"#e01e5a\";\n const durationSec = (payload.duration / 1000).toFixed(1);\n\n const fields: Array<{ title: string; value: string; short: boolean }> = [\n { title: \"Command\", value: payload.command, short: true },\n { title: \"Duration\", value: `${durationSec}s`, short: true },\n ];\n\n if (payload.app) {\n fields.push({ title: \"App\", value: payload.app, short: true });\n }\n\n if (payload.error) {\n fields.push({ title: \"Error\", value: payload.error, short: false });\n }\n\n if (payload.details) {\n for (const [key, value] of Object.entries(payload.details)) {\n fields.push({ title: key, value: String(value), short: true });\n }\n }\n\n return {\n attachments: [\n {\n color,\n fallback: `GPC: ${payload.command} ${status}`,\n title: `GPC: ${payload.command} ${status}`,\n fields,\n footer: \"GPC CLI\",\n ts: Math.floor(Date.now() / 1000),\n },\n ],\n };\n}\n\nexport function formatDiscordPayload(payload: WebhookPayload): object {\n const status = payload.success ? \"\\u2713\" : \"\\u2717\";\n const color = payload.success ? 0x2eb886 : 0xe01e5a;\n const durationSec = (payload.duration / 1000).toFixed(1);\n\n const fields: Array<{ name: string; value: string; inline: boolean }> = [\n { name: \"Command\", value: payload.command, inline: true },\n { name: \"Duration\", value: `${durationSec}s`, inline: true },\n ];\n\n if (payload.app) {\n fields.push({ name: \"App\", value: payload.app, inline: true });\n }\n\n if (payload.error) {\n fields.push({ name: \"Error\", value: payload.error, inline: false });\n }\n\n if (payload.details) {\n for (const [key, value] of Object.entries(payload.details)) {\n fields.push({ name: key, value: String(value), inline: true });\n }\n }\n\n return {\n embeds: [\n {\n title: `GPC: ${payload.command} ${status}`,\n color,\n fields,\n footer: { text: \"GPC CLI\" },\n timestamp: new Date().toISOString(),\n },\n ],\n };\n}\n\nexport function formatCustomPayload(payload: WebhookPayload): object {\n return { ...payload };\n}\n\ntype WebhookTarget = \"slack\" | \"discord\" | \"custom\";\n\nconst FORMATTERS: Record<WebhookTarget, (p: WebhookPayload) => object> = {\n slack: formatSlackPayload,\n discord: formatDiscordPayload,\n custom: formatCustomPayload,\n};\n\nconst WEBHOOK_TIMEOUT_MS = 5000;\n\nasync function sendSingle(url: string, body: object): Promise<void> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), WEBHOOK_TIMEOUT_MS);\n\n try {\n await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function sendWebhook(\n config: WebhookConfig,\n payload: WebhookPayload,\n target?: string,\n): Promise<void> {\n try {\n const targets: WebhookTarget[] = target\n ? [target as WebhookTarget]\n : (Object.keys(FORMATTERS) as WebhookTarget[]);\n\n const promises: Promise<void>[] = [];\n\n for (const t of targets) {\n const url = config[t];\n if (!url) continue;\n\n const formatter = FORMATTERS[t];\n if (!formatter) continue;\n\n const body = formatter(payload);\n promises.push(sendSingle(url, body).catch(() => {}));\n }\n\n await Promise.all(promises);\n } catch {\n // Never throw — webhook failures must not break the CLI\n }\n}\n","import { extname } from \"node:path\";\nimport type { PlayApiClient, InternalAppSharingArtifact } from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\nimport { validateUploadFile } from \"../utils/file-validation.js\";\n\nexport interface InternalSharingUploadResult {\n downloadUrl: string;\n sha256: string;\n certificateFingerprint: string;\n fileType: \"bundle\" | \"apk\";\n}\n\nexport async function uploadInternalSharing(\n client: PlayApiClient,\n packageName: string,\n filePath: string,\n fileType?: \"bundle\" | \"apk\",\n): Promise<InternalSharingUploadResult> {\n // Auto-detect file type from extension if not provided\n const resolvedType = fileType ?? detectFileType(filePath);\n\n // Validate the file\n const validation = await validateUploadFile(filePath);\n if (!validation.valid) {\n throw new GpcError(\n `File validation failed:\\n${validation.errors.join(\"\\n\")}`,\n \"INTERNAL_SHARING_INVALID_FILE\",\n 2,\n \"Check that the file is a valid AAB or APK and is not corrupted.\",\n );\n }\n\n let artifact: InternalAppSharingArtifact;\n if (resolvedType === \"bundle\") {\n artifact = await client.internalAppSharing.uploadBundle(packageName, filePath);\n } else {\n artifact = await client.internalAppSharing.uploadApk(packageName, filePath);\n }\n\n return {\n downloadUrl: artifact.downloadUrl,\n sha256: artifact.sha256,\n certificateFingerprint: artifact.certificateFingerprint,\n fileType: resolvedType,\n };\n}\n\nfunction detectFileType(filePath: string): \"bundle\" | \"apk\" {\n const ext = extname(filePath).toLowerCase();\n if (ext === \".aab\") return \"bundle\";\n if (ext === \".apk\") return \"apk\";\n throw new GpcError(\n `Cannot detect file type from extension \"${ext}\". Use --type to specify bundle or apk.`,\n \"INTERNAL_SHARING_UNKNOWN_TYPE\",\n 2,\n \"Use --type bundle for .aab files or --type apk for .apk files.\",\n );\n}\n","import { writeFile } from \"node:fs/promises\";\nimport type { PlayApiClient, GeneratedApk } from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\n\nexport async function listGeneratedApks(\n client: PlayApiClient,\n packageName: string,\n versionCode: number,\n): Promise<GeneratedApk[]> {\n if (!Number.isInteger(versionCode) || versionCode <= 0) {\n throw new GpcError(\n `Invalid version code: ${versionCode}`,\n \"GENERATED_APKS_INVALID_VERSION\",\n 2,\n \"Provide a positive integer version code.\",\n );\n }\n return client.generatedApks.list(packageName, versionCode);\n}\n\nexport async function downloadGeneratedApk(\n client: PlayApiClient,\n packageName: string,\n versionCode: number,\n apkId: string,\n outputPath: string,\n): Promise<{ path: string; sizeBytes: number }> {\n if (!Number.isInteger(versionCode) || versionCode <= 0) {\n throw new GpcError(\n `Invalid version code: ${versionCode}`,\n \"GENERATED_APKS_INVALID_VERSION\",\n 2,\n \"Provide a positive integer version code.\",\n );\n }\n\n if (!apkId) {\n throw new GpcError(\n \"APK ID is required\",\n \"GENERATED_APKS_MISSING_ID\",\n 2,\n \"Provide the generated APK ID. Use 'gpc generated-apks list <version-code>' to see available APKs.\",\n );\n }\n\n const buffer = await client.generatedApks.download(packageName, versionCode, apkId);\n const bytes = new Uint8Array(buffer);\n await writeFile(outputPath, bytes);\n\n return { path: outputPath, sizeBytes: bytes.byteLength };\n}\n","import type { PlayApiClient, PurchaseOption, PurchaseOptionsListResponse } from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\n\nexport async function listPurchaseOptions(\n client: PlayApiClient,\n packageName: string,\n): Promise<PurchaseOptionsListResponse> {\n try {\n return await client.purchaseOptions.list(packageName);\n } catch (error) {\n throw new GpcError(\n `Failed to list purchase options: ${error instanceof Error ? error.message : String(error)}`,\n \"PURCHASE_OPTIONS_LIST_FAILED\",\n 4,\n \"Check your package name and API permissions.\",\n );\n }\n}\n\nexport async function getPurchaseOption(\n client: PlayApiClient,\n packageName: string,\n purchaseOptionId: string,\n): Promise<PurchaseOption> {\n try {\n return await client.purchaseOptions.get(packageName, purchaseOptionId);\n } catch (error) {\n throw new GpcError(\n `Failed to get purchase option \"${purchaseOptionId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"PURCHASE_OPTION_GET_FAILED\",\n 4,\n \"Check that the purchase option ID exists.\",\n );\n }\n}\n\nexport async function createPurchaseOption(\n client: PlayApiClient,\n packageName: string,\n data: PurchaseOption,\n): Promise<PurchaseOption> {\n try {\n return await client.purchaseOptions.create(packageName, data);\n } catch (error) {\n throw new GpcError(\n `Failed to create purchase option: ${error instanceof Error ? error.message : String(error)}`,\n \"PURCHASE_OPTION_CREATE_FAILED\",\n 4,\n \"Check your purchase option data and API permissions.\",\n );\n }\n}\n\nexport async function activatePurchaseOption(\n client: PlayApiClient,\n packageName: string,\n purchaseOptionId: string,\n): Promise<PurchaseOption> {\n try {\n return await client.purchaseOptions.activate(packageName, purchaseOptionId);\n } catch (error) {\n throw new GpcError(\n `Failed to activate purchase option \"${purchaseOptionId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"PURCHASE_OPTION_ACTIVATE_FAILED\",\n 4,\n \"Check that the purchase option exists and is in a valid state for activation.\",\n );\n }\n}\n\nexport async function deactivatePurchaseOption(\n client: PlayApiClient,\n packageName: string,\n purchaseOptionId: string,\n): Promise<PurchaseOption> {\n try {\n return await client.purchaseOptions.deactivate(packageName, purchaseOptionId);\n } catch (error) {\n throw new GpcError(\n `Failed to deactivate purchase option \"${purchaseOptionId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"PURCHASE_OPTION_DEACTIVATE_FAILED\",\n 4,\n \"Check that the purchase option exists and is in a valid state for deactivation.\",\n );\n }\n}\n","import { readFile, stat } from \"node:fs/promises\";\n\nexport interface BundleEntry {\n path: string;\n module: string;\n category: string;\n compressedSize: number;\n uncompressedSize: number;\n}\n\nexport interface BundleAnalysis {\n filePath: string;\n fileType: \"aab\" | \"apk\";\n totalCompressed: number;\n totalUncompressed: number;\n entryCount: number;\n modules: { name: string; compressedSize: number; uncompressedSize: number; entries: number }[];\n categories: { name: string; compressedSize: number; uncompressedSize: number; entries: number }[];\n entries: BundleEntry[];\n}\n\nexport interface BundleComparison {\n before: { path: string; totalCompressed: number };\n after: { path: string; totalCompressed: number };\n sizeDelta: number;\n sizeDeltaPercent: number;\n moduleDeltas: { module: string; before: number; after: number; delta: number }[];\n categoryDeltas: { category: string; before: number; after: number; delta: number }[];\n}\n\nconst EOCD_SIGNATURE = 0x06054b50;\nconst CD_SIGNATURE = 0x02014b50;\n\n/** Known AAB module subdirs that distinguish feature modules from arbitrary top-level dirs. */\nconst MODULE_SUBDIRS = new Set([\"dex\", \"manifest\", \"res\", \"assets\", \"lib\", \"resources.pb\", \"root\"]);\n\nfunction detectCategory(path: string): string {\n const lower = path.toLowerCase();\n // dex files\n if (lower.endsWith(\".dex\") || /\\/dex\\/[^/]+\\.dex$/.test(lower)) return \"dex\";\n // resources\n if (\n lower === \"resources.arsc\" ||\n lower.endsWith(\"/resources.arsc\") ||\n lower.endsWith(\"/resources.pb\") ||\n /^(([^/]+\\/)?res\\/)/.test(lower)\n )\n return \"resources\";\n // assets\n if (/^(([^/]+\\/)?assets\\/)/.test(lower)) return \"assets\";\n // native libs\n if (/^(([^/]+\\/)?lib\\/)/.test(lower)) return \"native-libs\";\n // manifest\n if (\n lower === \"androidmanifest.xml\" ||\n lower.endsWith(\"/androidmanifest.xml\") ||\n /^(([^/]+\\/)?manifest\\/)/.test(lower)\n )\n return \"manifest\";\n // signing\n if (lower.startsWith(\"meta-inf/\") || lower === \"meta-inf\") return \"signing\";\n return \"other\";\n}\n\nfunction detectModule(path: string, isAab: boolean): string {\n if (!isAab) return \"(root)\";\n\n const slashIdx = path.indexOf(\"/\");\n if (slashIdx === -1) return \"(root)\";\n\n const topDir = path.substring(0, slashIdx);\n const rest = path.substring(slashIdx + 1);\n\n // \"base/\" module\n if (topDir === \"base\") return \"base\";\n\n // Root-level metadata\n if (topDir === \"BUNDLE-METADATA\" || topDir === \"META-INF\") return \"(root)\";\n if (path === \"BundleConfig.pb\") return \"(root)\";\n\n // Check if subdirectory matches known module structure\n const subDir = rest.split(\"/\")[0] || \"\";\n if (MODULE_SUBDIRS.has(subDir)) return topDir;\n\n return \"(root)\";\n}\n\ninterface CentralDirectoryEntry {\n filename: string;\n compressedSize: number;\n uncompressedSize: number;\n}\n\nfunction parseCentralDirectory(buf: Buffer): CentralDirectoryEntry[] {\n // Find EOCD — scan backwards from end (minimum EOCD is 22 bytes)\n let eocdOffset = -1;\n for (let i = buf.length - 22; i >= 0 && i >= buf.length - 65557; i--) {\n if (buf.readUInt32LE(i) === EOCD_SIGNATURE) {\n eocdOffset = i;\n break;\n }\n }\n if (eocdOffset === -1) {\n throw new Error(\"Not a valid ZIP file: EOCD signature not found\");\n }\n\n const cdSize = buf.readUInt32LE(eocdOffset + 12);\n let cdOffset = buf.readUInt32LE(eocdOffset + 16);\n\n // Handle ZIP64 — if offset is 0xFFFFFFFF, look for ZIP64 EOCD locator\n if (cdOffset === 0xffffffff) {\n // ZIP64 end of central directory locator is 20 bytes before EOCD\n const zip64LocatorOffset = eocdOffset - 20;\n if (zip64LocatorOffset >= 0 && buf.readUInt32LE(zip64LocatorOffset) === 0x07064b50) {\n // ZIP64 EOCD is at offset stored in locator bytes 8-15\n const zip64EocdOffset = Number(buf.readBigUInt64LE(zip64LocatorOffset + 8));\n if (zip64EocdOffset >= 0 && zip64EocdOffset < buf.length) {\n cdOffset = Number(buf.readBigUInt64LE(zip64EocdOffset + 48));\n }\n }\n }\n\n const entries: CentralDirectoryEntry[] = [];\n let pos = cdOffset;\n const end = cdOffset + cdSize;\n\n while (pos < end && pos + 46 <= buf.length) {\n const sig = buf.readUInt32LE(pos);\n if (sig !== CD_SIGNATURE) break;\n\n const compressedSize = buf.readUInt32LE(pos + 20);\n const uncompressedSize = buf.readUInt32LE(pos + 24);\n const filenameLen = buf.readUInt16LE(pos + 28);\n const extraLen = buf.readUInt16LE(pos + 30);\n const commentLen = buf.readUInt16LE(pos + 32);\n\n const filename = buf.toString(\"utf-8\", pos + 46, pos + 46 + filenameLen);\n\n // Skip directory entries (trailing slash)\n if (!filename.endsWith(\"/\")) {\n entries.push({ filename, compressedSize, uncompressedSize });\n }\n\n pos += 46 + filenameLen + extraLen + commentLen;\n }\n\n return entries;\n}\n\nfunction detectFileType(filePath: string): \"aab\" | \"apk\" {\n const lower = filePath.toLowerCase();\n if (lower.endsWith(\".aab\")) return \"aab\";\n return \"apk\";\n}\n\nexport async function analyzeBundle(filePath: string): Promise<BundleAnalysis> {\n const fileInfo = await stat(filePath).catch(() => null);\n if (!fileInfo || !fileInfo.isFile()) {\n throw new Error(`File not found: ${filePath}`);\n }\n\n const buf = await readFile(filePath);\n const cdEntries = parseCentralDirectory(buf);\n const fileType = detectFileType(filePath);\n const isAab = fileType === \"aab\";\n\n const entries: BundleEntry[] = cdEntries.map((e) => ({\n path: e.filename,\n module: detectModule(e.filename, isAab),\n category: detectCategory(e.filename),\n compressedSize: e.compressedSize,\n uncompressedSize: e.uncompressedSize,\n }));\n\n // Aggregate by module\n const moduleMap = new Map<\n string,\n { compressedSize: number; uncompressedSize: number; entries: number }\n >();\n for (const entry of entries) {\n const existing = moduleMap.get(entry.module) ?? {\n compressedSize: 0,\n uncompressedSize: 0,\n entries: 0,\n };\n existing.compressedSize += entry.compressedSize;\n existing.uncompressedSize += entry.uncompressedSize;\n existing.entries += 1;\n moduleMap.set(entry.module, existing);\n }\n\n // Aggregate by category\n const categoryMap = new Map<\n string,\n { compressedSize: number; uncompressedSize: number; entries: number }\n >();\n for (const entry of entries) {\n const existing = categoryMap.get(entry.category) ?? {\n compressedSize: 0,\n uncompressedSize: 0,\n entries: 0,\n };\n existing.compressedSize += entry.compressedSize;\n existing.uncompressedSize += entry.uncompressedSize;\n existing.entries += 1;\n categoryMap.set(entry.category, existing);\n }\n\n const modules = [...moduleMap.entries()]\n .map(([name, data]) => ({ name, ...data }))\n .sort((a, b) => b.compressedSize - a.compressedSize);\n\n const categories = [...categoryMap.entries()]\n .map(([name, data]) => ({ name, ...data }))\n .sort((a, b) => b.compressedSize - a.compressedSize);\n\n const totalCompressed = entries.reduce((sum, e) => sum + e.compressedSize, 0);\n const totalUncompressed = entries.reduce((sum, e) => sum + e.uncompressedSize, 0);\n\n return {\n filePath,\n fileType,\n totalCompressed,\n totalUncompressed,\n entryCount: entries.length,\n modules,\n categories,\n entries,\n };\n}\n\nexport function compareBundles(before: BundleAnalysis, after: BundleAnalysis): BundleComparison {\n const sizeDelta = after.totalCompressed - before.totalCompressed;\n const sizeDeltaPercent =\n before.totalCompressed > 0\n ? Math.round((sizeDelta / before.totalCompressed) * 100 * 10) / 10\n : 0;\n\n // Module deltas\n const allModules = new Set([\n ...before.modules.map((m) => m.name),\n ...after.modules.map((m) => m.name),\n ]);\n const moduleDeltas = [...allModules]\n .map((module) => {\n const b = before.modules.find((m) => m.name === module)?.compressedSize ?? 0;\n const a = after.modules.find((m) => m.name === module)?.compressedSize ?? 0;\n return { module, before: b, after: a, delta: a - b };\n })\n .sort((a, b) => Math.abs(b.delta) - Math.abs(a.delta));\n\n // Category deltas\n const allCategories = new Set([\n ...before.categories.map((c) => c.name),\n ...after.categories.map((c) => c.name),\n ]);\n const categoryDeltas = [...allCategories]\n .map((category) => {\n const b = before.categories.find((c) => c.name === category)?.compressedSize ?? 0;\n const a = after.categories.find((c) => c.name === category)?.compressedSize ?? 0;\n return { category, before: b, after: a, delta: a - b };\n })\n .sort((a, b) => Math.abs(b.delta) - Math.abs(a.delta));\n\n return {\n before: { path: before.filePath, totalCompressed: before.totalCompressed },\n after: { path: after.filePath, totalCompressed: after.totalCompressed },\n sizeDelta,\n sizeDeltaPercent,\n moduleDeltas,\n categoryDeltas,\n };\n}\n\n/** Return the top N largest files by compressed size. */\nexport function topFiles(analysis: BundleAnalysis, n: number = 20): BundleEntry[] {\n return [...analysis.entries].sort((a, b) => b.compressedSize - a.compressedSize).slice(0, n);\n}\n\nexport interface BundleSizeConfig {\n maxTotalCompressed?: number;\n modules?: Record<string, { maxCompressed: number }>;\n}\n\nexport interface BundleSizeCheckResult {\n passed: boolean;\n violations: Array<{ subject: string; actual: number; max: number }>;\n}\n\n/** Check bundle analysis against .bundlesize.json thresholds. */\nexport async function checkBundleSize(\n analysis: BundleAnalysis,\n configPath: string = \".bundlesize.json\",\n): Promise<BundleSizeCheckResult> {\n let config: BundleSizeConfig;\n try {\n const raw = await readFile(configPath, \"utf-8\");\n config = JSON.parse(raw) as BundleSizeConfig;\n } catch {\n return { passed: true, violations: [] };\n }\n\n const violations: BundleSizeCheckResult[\"violations\"] = [];\n\n if (\n config.maxTotalCompressed !== undefined &&\n analysis.totalCompressed > config.maxTotalCompressed\n ) {\n violations.push({\n subject: \"total\",\n actual: analysis.totalCompressed,\n max: config.maxTotalCompressed,\n });\n }\n\n if (config.modules) {\n for (const [moduleName, threshold] of Object.entries(config.modules)) {\n const mod = analysis.modules.find((m) => m.name === moduleName);\n if (mod && mod.compressedSize > threshold.maxCompressed) {\n violations.push({\n subject: `module:${moduleName}`,\n actual: mod.compressedSize,\n max: threshold.maxCompressed,\n });\n }\n }\n }\n\n return { passed: violations.length === 0, violations };\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { execFile } from \"node:child_process\";\nimport { join } from \"node:path\";\nimport type { PlayApiClient } from \"@gpc-cli/api\";\nimport type { ReportingApiClient } from \"@gpc-cli/api\";\nimport { getCacheDir } from \"@gpc-cli/config\";\nimport { getReleasesStatus } from \"./releases.js\";\nimport { listReviews } from \"./reviews.js\";\nimport type { VitalsMetricSet, MetricSetQuery } from \"@gpc-cli/api\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface StatusVitalMetric {\n value: number | undefined;\n threshold: number;\n status: \"ok\" | \"warn\" | \"breach\" | \"unknown\";\n previousValue?: number | undefined;\n trend?: \"up\" | \"down\" | \"flat\" | null;\n}\n\nexport interface StatusRelease {\n track: string;\n versionCode: string;\n status: string;\n userFraction: number | null;\n}\n\nexport interface StatusReviews {\n windowDays: number;\n averageRating: number | undefined;\n previousAverageRating: number | undefined;\n totalNew: number;\n positivePercent: number | undefined;\n}\n\nexport interface AppStatus {\n packageName: string;\n fetchedAt: string;\n cached: boolean;\n sections: string[]; // active sections: \"releases\" | \"vitals\" | \"reviews\"\n releases: StatusRelease[];\n vitals: {\n windowDays: number;\n crashes: StatusVitalMetric;\n anr: StatusVitalMetric;\n slowStarts: StatusVitalMetric;\n slowRender: StatusVitalMetric;\n };\n reviews: StatusReviews;\n}\n\nexport interface StatusDiff {\n versionCode: { from: string | null; to: string | null };\n crashRate: { from: number | null; to: number | null; delta: number | null };\n anrRate: { from: number | null; to: number | null; delta: number | null };\n reviewCount: { from: number | null; to: number | null };\n averageRating: { from: number | null; to: number | null; delta: number | null };\n}\n\nexport interface GetAppStatusOptions {\n days?: number;\n reviewDays?: number;\n sections?: string[]; // \"releases\" | \"vitals\" | \"reviews\"\n vitalThresholds?: {\n crashRate?: number;\n anrRate?: number;\n slowStartRate?: number;\n slowRenderingRate?: number;\n };\n}\n\nexport interface WatchOptions {\n intervalSeconds: number;\n render: (status: AppStatus) => string;\n fetch: () => Promise<AppStatus>;\n save: (status: AppStatus) => Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// Cache\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_TTL_SECONDS = 3600;\n\ninterface CacheEntry {\n fetchedAt: string;\n ttl: number;\n data: AppStatus;\n}\n\nfunction cacheFilePath(packageName: string): string {\n return join(getCacheDir(), `status-${packageName}.json`);\n}\n\nexport async function loadStatusCache(\n packageName: string,\n ttlSeconds = DEFAULT_TTL_SECONDS,\n): Promise<AppStatus | null> {\n try {\n const raw = await readFile(cacheFilePath(packageName), \"utf-8\");\n const entry = JSON.parse(raw) as CacheEntry;\n const age = (Date.now() - new Date(entry.fetchedAt).getTime()) / 1000;\n if (age > (entry.ttl ?? ttlSeconds)) return null;\n const data = entry.data;\n return {\n ...data,\n sections: data.sections ?? [\"releases\", \"vitals\", \"reviews\"],\n cached: true,\n };\n } catch {\n return null;\n }\n}\n\nexport async function saveStatusCache(\n packageName: string,\n data: AppStatus,\n ttlSeconds = DEFAULT_TTL_SECONDS,\n): Promise<void> {\n try {\n const dir = getCacheDir();\n await mkdir(dir, { recursive: true });\n const entry: CacheEntry = { fetchedAt: data.fetchedAt, ttl: ttlSeconds, data };\n await writeFile(cacheFilePath(packageName), JSON.stringify(entry, null, 2), {\n encoding: \"utf-8\",\n mode: 0o600,\n });\n } catch {\n // Cache write failures must never break the command\n }\n}\n\n// ---------------------------------------------------------------------------\n// Vitals helpers\n// ---------------------------------------------------------------------------\n\nconst METRIC_SET_METRICS: Partial<Record<VitalsMetricSet, string[]>> = {\n crashRateMetricSet: [\"crashRate\", \"userPerceivedCrashRate\", \"distinctUsers\"],\n anrRateMetricSet: [\"anrRate\", \"userPerceivedAnrRate\", \"distinctUsers\"],\n slowStartRateMetricSet: [\"slowStartRate\", \"distinctUsers\"],\n slowRenderingRateMetricSet: [\"slowRenderingRate\", \"distinctUsers\"],\n};\n\nconst DEFAULT_THRESHOLDS = {\n crashRate: 0.02,\n anrRate: 0.01,\n slowStartRate: 0.05,\n slowRenderingRate: 0.1,\n};\n\nconst WARN_MARGIN = 0.2; // within 20% of threshold → warn\n\nfunction toApiDate(d: Date): { year: number; month: number; day: number } {\n return { year: d.getUTCFullYear(), month: d.getUTCMonth() + 1, day: d.getUTCDate() };\n}\n\nasync function queryVitalForStatus(\n reporting: ReportingApiClient,\n packageName: string,\n metricSet: VitalsMetricSet,\n days: number,\n offsetDays = 0,\n): Promise<number | undefined> {\n const DAY_MS = 24 * 60 * 60 * 1000;\n const baseMs = Date.now() - 2 * DAY_MS - offsetDays * DAY_MS;\n const end = new Date(baseMs);\n const start = new Date(baseMs - days * DAY_MS);\n const metrics = METRIC_SET_METRICS[metricSet] ?? [\"distinctUsers\"];\n\n const query: MetricSetQuery = {\n metrics,\n timelineSpec: {\n aggregationPeriod: \"DAILY\",\n startTime: toApiDate(start),\n endTime: toApiDate(end),\n },\n };\n\n const result = await reporting.queryMetricSet(packageName, metricSet, query);\n if (!result.rows || result.rows.length === 0) return undefined;\n\n const values = result.rows\n .map((row) => {\n const firstKey = Object.keys(row.metrics)[0];\n return firstKey ? Number(row.metrics[firstKey]?.decimalValue?.value) : NaN;\n })\n .filter((v) => !isNaN(v));\n\n if (values.length === 0) return undefined;\n return values.reduce((a, b) => a + b, 0) / values.length;\n}\n\ninterface VitalWithTrend {\n current: number | undefined;\n previous: number | undefined;\n trend: \"up\" | \"down\" | \"flat\" | null;\n}\n\nasync function queryVitalWithTrend(\n reporting: ReportingApiClient,\n packageName: string,\n metricSet: VitalsMetricSet,\n days: number,\n): Promise<VitalWithTrend> {\n const [current, previous] = await Promise.all([\n queryVitalForStatus(reporting, packageName, metricSet, days, 0),\n queryVitalForStatus(reporting, packageName, metricSet, days, days),\n ]);\n\n let trend: \"up\" | \"down\" | \"flat\" | null = null;\n if (current !== undefined && previous !== undefined) {\n if (current > previous) trend = \"up\";\n else if (current < previous) trend = \"down\";\n else trend = \"flat\";\n }\n\n return { current, previous, trend };\n}\n\nconst SKIPPED_VITAL: VitalWithTrend = { current: undefined, previous: undefined, trend: null };\n\nfunction toVitalMetric(\n value: number | undefined,\n threshold: number,\n previousValue?: number | undefined,\n trend?: \"up\" | \"down\" | \"flat\" | null,\n): StatusVitalMetric {\n const base: StatusVitalMetric =\n previousValue !== undefined\n ? { value, threshold, status: \"unknown\", previousValue, trend: trend ?? null }\n : { value, threshold, status: \"unknown\" };\n\n if (value === undefined) return { ...base, status: \"unknown\" };\n if (value > threshold) return { ...base, status: \"breach\" };\n if (value > threshold * (1 - WARN_MARGIN)) return { ...base, status: \"warn\" };\n return { ...base, status: \"ok\" };\n}\n\n// ---------------------------------------------------------------------------\n// Reviews helpers\n// ---------------------------------------------------------------------------\n\nfunction computeReviewSentiment(\n reviews: Awaited<ReturnType<typeof listReviews>>,\n windowDays: number,\n): StatusReviews {\n const now = Date.now();\n const DAY_MS = 24 * 60 * 60 * 1000;\n const windowMs = windowDays * DAY_MS;\n const prevWindowStart = now - 2 * windowMs;\n const curWindowStart = now - windowMs;\n\n const current = reviews.filter((r) => {\n const uc = r.comments?.[0]?.userComment;\n if (!uc) return false;\n const ts = Number(uc.lastModified.seconds) * 1000;\n return ts >= curWindowStart;\n });\n\n const previous = reviews.filter((r) => {\n const uc = r.comments?.[0]?.userComment;\n if (!uc) return false;\n const ts = Number(uc.lastModified.seconds) * 1000;\n return ts >= prevWindowStart && ts < curWindowStart;\n });\n\n const avgRating = (items: typeof reviews): number | undefined => {\n const ratings = items\n .map((r) => r.comments?.[0]?.userComment?.starRating)\n .filter((v): v is number => v !== undefined && v > 0);\n if (ratings.length === 0) return undefined;\n return Math.round((ratings.reduce((a, b) => a + b, 0) / ratings.length) * 10) / 10;\n };\n\n const positiveCount = current.filter(\n (r) => (r.comments?.[0]?.userComment?.starRating ?? 0) >= 4,\n ).length;\n\n const positivePercent =\n current.length > 0 ? Math.round((positiveCount / current.length) * 100) : undefined;\n\n return {\n windowDays,\n averageRating: avgRating(current),\n previousAverageRating: avgRating(previous),\n totalNew: current.length,\n positivePercent,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Main orchestrator\n// ---------------------------------------------------------------------------\n\nexport async function getAppStatus(\n client: PlayApiClient,\n reporting: ReportingApiClient,\n packageName: string,\n options: GetAppStatusOptions = {},\n): Promise<AppStatus> {\n const days = options.days ?? 7;\n const reviewDays = options.reviewDays ?? 30;\n const sections = new Set(options.sections ?? [\"releases\", \"vitals\", \"reviews\"]);\n const thresholds = {\n crashRate: options.vitalThresholds?.crashRate ?? DEFAULT_THRESHOLDS.crashRate,\n anrRate: options.vitalThresholds?.anrRate ?? DEFAULT_THRESHOLDS.anrRate,\n slowStartRate: options.vitalThresholds?.slowStartRate ?? DEFAULT_THRESHOLDS.slowStartRate,\n slowRenderingRate:\n options.vitalThresholds?.slowRenderingRate ?? DEFAULT_THRESHOLDS.slowRenderingRate,\n };\n\n const [\n releasesResult,\n crashesResult,\n anrResult,\n slowStartResult,\n slowRenderResult,\n reviewsResult,\n ] = await Promise.allSettled([\n sections.has(\"releases\") ? getReleasesStatus(client, packageName) : Promise.resolve([]),\n sections.has(\"vitals\")\n ? queryVitalWithTrend(reporting, packageName, \"crashRateMetricSet\", days)\n : Promise.resolve(SKIPPED_VITAL),\n sections.has(\"vitals\")\n ? queryVitalWithTrend(reporting, packageName, \"anrRateMetricSet\", days)\n : Promise.resolve(SKIPPED_VITAL),\n sections.has(\"vitals\")\n ? queryVitalWithTrend(reporting, packageName, \"slowStartRateMetricSet\", days)\n : Promise.resolve(SKIPPED_VITAL),\n sections.has(\"vitals\")\n ? queryVitalWithTrend(reporting, packageName, \"slowRenderingRateMetricSet\", days)\n : Promise.resolve(SKIPPED_VITAL),\n sections.has(\"reviews\")\n ? listReviews(client, packageName, { maxResults: 500 })\n : Promise.resolve([]),\n ]);\n\n const rawReleases = releasesResult.status === \"fulfilled\" ? releasesResult.value : [];\n const releases: StatusRelease[] = rawReleases.map((r) => ({\n track: r.track,\n versionCode: r.versionCodes[r.versionCodes.length - 1] ?? \"—\",\n status: r.status,\n userFraction: r.userFraction ?? null,\n }));\n\n const crashes = crashesResult.status === \"fulfilled\" ? crashesResult.value : SKIPPED_VITAL;\n const anr = anrResult.status === \"fulfilled\" ? anrResult.value : SKIPPED_VITAL;\n const slowStart = slowStartResult.status === \"fulfilled\" ? slowStartResult.value : SKIPPED_VITAL;\n const slowRender =\n slowRenderResult.status === \"fulfilled\" ? slowRenderResult.value : SKIPPED_VITAL;\n\n const rawReviews = reviewsResult.status === \"fulfilled\" ? reviewsResult.value : [];\n const reviews = computeReviewSentiment(rawReviews, reviewDays);\n\n return {\n packageName,\n fetchedAt: new Date().toISOString(),\n cached: false,\n sections: [...sections],\n releases,\n vitals: {\n windowDays: days,\n crashes: toVitalMetric(\n crashes.current,\n thresholds.crashRate,\n crashes.previous,\n crashes.trend,\n ),\n anr: toVitalMetric(anr.current, thresholds.anrRate, anr.previous, anr.trend),\n slowStarts: toVitalMetric(\n slowStart.current,\n thresholds.slowStartRate,\n slowStart.previous,\n slowStart.trend,\n ),\n slowRender: toVitalMetric(\n slowRender.current,\n thresholds.slowRenderingRate,\n slowRender.previous,\n slowRender.trend,\n ),\n },\n reviews,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Table formatter\n// ---------------------------------------------------------------------------\n\nfunction vitalIndicator(metric: StatusVitalMetric): string {\n if (metric.status === \"unknown\") return \"—\";\n if (metric.status === \"breach\") return \"✗\";\n if (metric.status === \"warn\") return \"⚠\";\n return \"✓\";\n}\n\n// For all vital metrics (crash rate, ANR, slow starts, slow render) lower is better:\n// trend \"up\" (increasing) is bad → ↑, trend \"down\" (decreasing) is good → ↓\nfunction vitalTrendArrow(metric: StatusVitalMetric): string {\n if (!metric.trend || metric.trend === \"flat\") return \"\";\n return metric.trend === \"up\" ? \" ↑\" : \" ↓\";\n}\n\nfunction formatVitalValue(metric: StatusVitalMetric): string {\n if (metric.value === undefined) return \"—\";\n return `${(metric.value * 100).toFixed(2)}%`;\n}\n\nfunction formatFraction(fraction: number | null): string {\n if (fraction === null) return \"—\";\n return `${Math.round(fraction * 100)}%`;\n}\n\nfunction formatRating(rating: number | undefined): string {\n if (rating === undefined) return \"—\";\n return `★ ${rating.toFixed(1)}`;\n}\n\nfunction formatTrend(current: number | undefined, previous: number | undefined): string {\n if (current === undefined || previous === undefined) return \"\";\n if (current > previous) return ` ↑ from ${previous.toFixed(1)}`;\n if (current < previous) return ` ↓ from ${previous.toFixed(1)}`;\n return \"\";\n}\n\nexport function relativeTime(isoString: string): string {\n const diffMs = Date.now() - new Date(isoString).getTime();\n const diffMin = Math.floor(diffMs / 60000);\n if (diffMin < 1) return \"just now\";\n if (diffMin < 60) return `${diffMin} min ago`;\n const diffHr = Math.floor(diffMin / 60);\n if (diffHr < 24) return `${diffHr}h ago`;\n return `${Math.floor(diffHr / 24)}d ago`;\n}\n\nfunction allVitalsUnknown(vitals: AppStatus[\"vitals\"]): boolean {\n return (\n vitals.crashes.status === \"unknown\" &&\n vitals.anr.status === \"unknown\" &&\n vitals.slowStarts.status === \"unknown\" &&\n vitals.slowRender.status === \"unknown\"\n );\n}\n\nexport function formatStatusTable(status: AppStatus): string {\n const lines: string[] = [];\n const sectionSet = new Set(status.sections);\n const cachedLabel = status.cached\n ? ` (cached ${relativeTime(status.fetchedAt)})`\n : ` (fetched ${relativeTime(status.fetchedAt)})`;\n\n lines.push(`App: ${status.packageName}${cachedLabel}`);\n\n // Releases\n if (sectionSet.has(\"releases\")) {\n lines.push(\"\");\n lines.push(\"RELEASES\");\n if (status.releases.length === 0) {\n lines.push(\" No releases found.\");\n } else {\n const trackW = Math.max(10, ...status.releases.map((r) => r.track.length));\n const versionW = Math.max(7, ...status.releases.map((r) => r.versionCode.length));\n const statusW = Math.max(8, ...status.releases.map((r) => r.status.length));\n for (const r of status.releases) {\n lines.push(\n ` ${r.track.padEnd(trackW)} ${r.versionCode.padEnd(versionW)} ${r.status.padEnd(statusW)} ${formatFraction(r.userFraction)}`,\n );\n }\n }\n }\n\n // Vitals\n if (sectionSet.has(\"vitals\")) {\n lines.push(\"\");\n lines.push(`VITALS (last ${status.vitals.windowDays} days)`);\n if (allVitalsUnknown(status.vitals)) {\n lines.push(\" No vitals data available for this period.\");\n } else {\n const { crashes, anr, slowStarts, slowRender } = status.vitals;\n const crashVal = `${formatVitalValue(crashes)}${vitalTrendArrow(crashes)}`;\n const anrVal = `${formatVitalValue(anr)}${vitalTrendArrow(anr)}`;\n const slowStartVal = `${formatVitalValue(slowStarts)}${vitalTrendArrow(slowStarts)}`;\n const slowRenderVal = `${formatVitalValue(slowRender)}${vitalTrendArrow(slowRender)}`;\n lines.push(\n ` crashes ${crashVal.padEnd(10)} ${vitalIndicator(crashes)} ` +\n `anr ${anrVal.padEnd(10)} ${vitalIndicator(anr)}`,\n );\n lines.push(\n ` slow starts ${slowStartVal.padEnd(10)} ${vitalIndicator(slowStarts)} ` +\n `slow render ${slowRenderVal.padEnd(10)} ${vitalIndicator(slowRender)}`,\n );\n }\n }\n\n // Reviews\n if (sectionSet.has(\"reviews\")) {\n lines.push(\"\");\n lines.push(`REVIEWS (last ${status.reviews.windowDays} days)`);\n const { averageRating, previousAverageRating, totalNew, positivePercent } = status.reviews;\n if (totalNew === 0 && averageRating === undefined) {\n lines.push(\" No reviews in this period.\");\n } else {\n const trend = formatTrend(averageRating, previousAverageRating);\n const positiveStr = positivePercent !== undefined ? ` ${positivePercent}% positive` : \"\";\n lines.push(` ${formatRating(averageRating)} ${totalNew} new${positiveStr}${trend}`);\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// Summary formatter (one-liner for --format summary)\n// ---------------------------------------------------------------------------\n\nexport function formatStatusSummary(status: AppStatus): string {\n const parts: string[] = [status.packageName];\n\n // Latest non-draft release\n const latestRelease = status.releases.find((r) => r.status !== \"draft\") ?? status.releases[0];\n if (latestRelease) {\n parts.push(`v${latestRelease.versionCode} ${latestRelease.track}`);\n }\n\n // Vitals (crashes + ANR only for brevity)\n const { crashes, anr } = status.vitals;\n const allVitalsUnknown = crashes.status === \"unknown\" && anr.status === \"unknown\";\n if (allVitalsUnknown) {\n parts.push(\"no vitals\");\n } else {\n if (crashes.status !== \"unknown\") {\n const arrow = crashes.trend === \"up\" ? \" ↑\" : crashes.trend === \"down\" ? \" ↓\" : \"\";\n parts.push(`crashes ${formatVitalValue(crashes)}${arrow} ${vitalIndicator(crashes)}`);\n }\n if (anr.status !== \"unknown\") {\n const arrow = anr.trend === \"up\" ? \" ↑\" : anr.trend === \"down\" ? \" ↓\" : \"\";\n parts.push(`ANR ${formatVitalValue(anr)}${arrow} ${vitalIndicator(anr)}`);\n }\n }\n\n // Reviews\n const { averageRating, totalNew } = status.reviews;\n if (averageRating !== undefined) {\n parts.push(`avg ${averageRating.toFixed(1)}★`);\n if (totalNew > 0) parts.push(`${totalNew} reviews`);\n } else {\n parts.push(\"no reviews\");\n }\n\n return parts.join(\" · \") + (statusHasBreach(status) ? \" [ALERT]\" : \"\");\n}\n\n// ---------------------------------------------------------------------------\n// Diff (--since-last)\n// ---------------------------------------------------------------------------\n\nfunction latestProductionVersion(releases: StatusRelease[]): string | null {\n const prod = releases.find((r) => r.track === \"production\");\n if (prod) return prod.versionCode;\n // Fallback: first non-draft release, then first release\n const nonDraft = releases.find((r) => r.status !== \"draft\");\n return nonDraft?.versionCode ?? releases[0]?.versionCode ?? null;\n}\n\nexport function computeStatusDiff(prev: AppStatus, curr: AppStatus): StatusDiff {\n const prevVersion = latestProductionVersion(prev.releases);\n const currVersion = latestProductionVersion(curr.releases);\n const prevCrash = prev.vitals.crashes.value ?? null;\n const currCrash = curr.vitals.crashes.value ?? null;\n const prevAnr = prev.vitals.anr.value ?? null;\n const currAnr = curr.vitals.anr.value ?? null;\n const prevRating = prev.reviews.averageRating ?? null;\n const currRating = curr.reviews.averageRating ?? null;\n\n return {\n versionCode: { from: prevVersion, to: currVersion },\n crashRate: {\n from: prevCrash,\n to: currCrash,\n delta: currCrash !== null && prevCrash !== null ? currCrash - prevCrash : null,\n },\n anrRate: {\n from: prevAnr,\n to: currAnr,\n delta: currAnr !== null && prevAnr !== null ? currAnr - prevAnr : null,\n },\n reviewCount: { from: prev.reviews.totalNew, to: curr.reviews.totalNew },\n averageRating: {\n from: prevRating,\n to: currRating,\n delta:\n currRating !== null && prevRating !== null\n ? Math.round((currRating - prevRating) * 10) / 10\n : null,\n },\n };\n}\n\nexport function formatStatusDiff(diff: StatusDiff, since: string): string {\n const lines: string[] = [`Changes since ${since}:`];\n\n if (diff.versionCode.from !== diff.versionCode.to) {\n lines.push(` Version: ${diff.versionCode.from ?? \"—\"} → ${diff.versionCode.to ?? \"—\"}`);\n }\n\n const fmtRate = (v: number | null): string => (v !== null ? `${(v * 100).toFixed(2)}%` : \"—\");\n\n const fmtDelta = (d: number | null, lowerIsBetter = true): string => {\n if (d === null || Math.abs(d) < 0.0001) return \"no change\";\n const sign = d > 0 ? \"+\" : \"\";\n const good = lowerIsBetter ? d < 0 : d > 0;\n return `${sign}${(d * 100).toFixed(2)}% ${good ? \"✓\" : \"✗\"}`;\n };\n\n lines.push(\n ` Crash rate: ${fmtRate(diff.crashRate.from)} → ${fmtRate(diff.crashRate.to)} (${fmtDelta(diff.crashRate.delta)})`,\n );\n lines.push(\n ` ANR rate: ${fmtRate(diff.anrRate.from)} → ${fmtRate(diff.anrRate.to)} (${fmtDelta(diff.anrRate.delta)})`,\n );\n\n const ratingDelta = diff.averageRating.delta;\n const prevR = diff.averageRating.from !== null ? `${diff.averageRating.from.toFixed(1)}★` : \"—\";\n const currR = diff.averageRating.to !== null ? `${diff.averageRating.to.toFixed(1)}★` : \"—\";\n const ratingStr =\n ratingDelta === null || Math.abs(ratingDelta) < 0.05\n ? \"no change\"\n : `${ratingDelta > 0 ? \"+\" : \"\"}${ratingDelta.toFixed(1)} ${ratingDelta > 0 ? \"✓\" : \"✗\"}`;\n lines.push(` Reviews: ${prevR} → ${currR} (${ratingStr})`);\n\n return lines.join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// Watch loop (--watch N)\n// ---------------------------------------------------------------------------\n\nexport async function runWatchLoop(opts: WatchOptions): Promise<void> {\n if (opts.intervalSeconds < 10) {\n throw new Error(\"--watch interval must be at least 10 seconds\");\n }\n\n let running = true;\n\n const cleanup = () => {\n running = false;\n };\n process.on(\"SIGINT\", cleanup);\n process.on(\"SIGTERM\", cleanup);\n\n while (running) {\n process.stdout.write(\"\\x1b[2J\\x1b[H\"); // clear terminal\n const fetchedAt = Date.now();\n\n try {\n const status = await opts.fetch();\n await opts.save(status);\n console.log(opts.render(status));\n } catch (err) {\n console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n // Sleep in 1s ticks so SIGINT is responsive, update footer with elapsed time\n for (let i = 0; i < opts.intervalSeconds && running; i++) {\n const elapsed = Math.round((Date.now() - fetchedAt) / 1000);\n const remaining = opts.intervalSeconds - i;\n process.stdout.write(\n `\\r[gpc status] Fetched ${elapsed}s ago · refreshing in ${remaining}s (Ctrl+C to stop)\\x1b[K`,\n );\n await new Promise<void>((r) => setTimeout(r, 1000));\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Notifications (--notify)\n// ---------------------------------------------------------------------------\n\nfunction breachStateFilePath(packageName: string): string {\n return join(getCacheDir(), `breach-state-${packageName}.json`);\n}\n\n/** Returns true if breach state changed (breach started or cleared). */\nexport async function trackBreachState(\n packageName: string,\n isBreaching: boolean,\n): Promise<boolean> {\n const filePath = breachStateFilePath(packageName);\n let prevBreaching = false;\n\n try {\n const raw = await readFile(filePath, \"utf-8\");\n prevBreaching = (JSON.parse(raw) as { breaching: boolean }).breaching;\n } catch {\n // No prior state — first run\n }\n\n if (prevBreaching !== isBreaching) {\n try {\n await mkdir(getCacheDir(), { recursive: true });\n await writeFile(\n filePath,\n JSON.stringify({ breaching: isBreaching, since: new Date().toISOString() }, null, 2),\n { encoding: \"utf-8\", mode: 0o600 },\n );\n } catch {\n // State write failure is non-fatal\n }\n return true;\n }\n return false;\n}\n\nexport function sendNotification(title: string, body: string): void {\n if (process.env[\"CI\"]) return; // Skip in CI environments\n\n try {\n const p = process.platform;\n if (p === \"darwin\") {\n // execFile avoids shell parsing; AppleScript string uses JSON.stringify for safe quoting\n execFile(\"osascript\", [\n \"-e\",\n `display notification ${JSON.stringify(body)} with title ${JSON.stringify(title)}`,\n ]);\n } else if (p === \"linux\") {\n // Pass title and body as separate argv elements — no shell, no escaping needed\n execFile(\"notify-send\", [title, body]);\n } else if (p === \"win32\") {\n // Escape single quotes for PowerShell literal strings; execFile skips shell parsing\n // so no double-quote injection risk from the outer command string\n const psEscape = (s: string) =>\n s\n .replace(/'/g, \"''\") // PS single-quote escape\n .replace(/[\\r\\n]/g, \" \"); // strip newlines that would break the -Command string\n execFile(\"powershell\", [\n \"-NoProfile\",\n \"-NonInteractive\",\n \"-Command\",\n `Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.MessageBox]::Show('${psEscape(body)}', '${psEscape(title)}')`,\n ]);\n }\n } catch {\n // Notification failures are non-fatal\n }\n}\n\n// ---------------------------------------------------------------------------\n// Status indicator for exit code (mirrors gpc vitals behaviour)\n// ---------------------------------------------------------------------------\n\nexport function statusHasBreach(status: AppStatus): boolean {\n return (\n status.vitals.crashes.status === \"breach\" ||\n status.vitals.anr.status === \"breach\" ||\n status.vitals.slowStarts.status === \"breach\" ||\n status.vitals.slowRender.status === \"breach\"\n );\n}\n","const GITHUB_RELEASES_URL =\n \"https://api.github.com/repos/yasserstudio/gpc/releases\";\n\nconst DOCS_CHANGELOG_URL =\n \"https://yasserstudio.github.io/gpc/reference/changelog\";\n\nexport interface ChangelogEntry {\n version: string;\n title: string;\n date: string;\n body: string;\n url: string;\n}\n\nexport interface FetchChangelogOptions {\n limit?: number;\n version?: string;\n}\n\n/**\n * Fetch release history from GitHub Releases API.\n * Public endpoint — no auth required (60 req/hour rate limit).\n */\nexport async function fetchChangelog(\n options?: FetchChangelogOptions,\n): Promise<ChangelogEntry[]> {\n const limit = options?.limit ?? 5;\n\n const url = options?.version\n ? `${GITHUB_RELEASES_URL}/tags/${options.version.startsWith(\"v\") ? options.version : `v${options.version}`}`\n : `${GITHUB_RELEASES_URL}?per_page=${Math.min(limit, 100)}`;\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 10_000);\n\n let response: Response;\n try {\n response = await fetch(url, {\n headers: {\n Accept: \"application/vnd.github+json\",\n \"User-Agent\": \"gpc-cli\",\n },\n signal: controller.signal,\n });\n } catch {\n throw new Error(\n `Could not fetch changelog. View online: ${DOCS_CHANGELOG_URL}`,\n );\n } finally {\n clearTimeout(timer);\n }\n\n if (!response.ok) {\n if (response.status === 404 && options?.version) {\n throw new Error(\n `Version ${options.version} not found. Run: gpc changelog --limit 10`,\n );\n }\n throw new Error(\n `GitHub API returned ${response.status}. View online: ${DOCS_CHANGELOG_URL}`,\n );\n }\n\n const data = await response.json();\n const releases: Array<{\n tag_name: string;\n name: string;\n published_at: string;\n body: string;\n html_url: string;\n }> = Array.isArray(data) ? data : [data];\n\n return releases\n .filter((r) => r.tag_name.startsWith(\"v\"))\n .map((r) => ({\n version: r.tag_name,\n title: r.name || r.tag_name,\n date: r.published_at ? r.published_at.split(\"T\")[0]! : \"unknown\",\n body: r.body || \"No release notes.\",\n url: r.html_url,\n }));\n}\n\n/**\n * Format a changelog entry as readable terminal text.\n * Strips markdown formatting for clean terminal output.\n */\nexport function formatChangelogEntry(entry: ChangelogEntry): string {\n const lines: string[] = [];\n lines.push(`${entry.version} — ${entry.title}`);\n lines.push(`Released: ${entry.date}`);\n lines.push(\"\");\n\n // Strip markdown formatting for terminal display\n const body = entry.body\n .replace(/^### /gm, \"\")\n .replace(/^## /gm, \"\")\n .replace(/^# /gm, \"\")\n .replace(/\\*\\*(.*?)\\*\\*/g, \"$1\")\n .replace(/`([^`]+)`/g, \"$1\")\n .replace(/\\[([^\\]]+)\\]\\([^)]+\\)/g, \"$1\")\n .trim();\n\n lines.push(body);\n lines.push(\"\");\n lines.push(`Full notes: ${entry.url}`);\n\n return lines.join(\"\\n\");\n}\n"],"mappings":"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","names":["process","resolve","stat","edit","stat","stat","extname","formatSize","stat","SAFE_LANG","i","j","mkdir","writeFile","join","readdir","readFile","writeFile","mkdir","join","readdir","readFile","stat","extname","join","readdir","extname","join","stat","readFile","stat","formatSize","stat","upload","analyzeReviews","paginateAll","paginateAll","toApiDate","readdir","readFile","join","paginateAll","paginateAll","readdir","readFile","join","paginateAll","dim","paginateAll","paginateAll","readFile","readFile","readFile","writeFile","writeFile","readFile","process","mkdir","readFile","writeFile","join","parseDuration","parseDuration","mkdir","readFile","writeFile","join","join","readFile","writeFile","mkdir","writeFile","stat","join","exists","readFile","readFile","resolve","readdir","stat","readFile","join","FILE_MAP","readdir","join","stat","readFile","readFile","readdir","stat","join","extname","readFile","readFile","SCAN_EXTENSIONS","readFile","readFile","SCAN_EXTENSIONS","readFile","mkdir","writeFile","join","extname","extname","writeFile","writeFile","readFile","stat","detectCategory","detectFileType","mkdir","readFile","writeFile","execFile","join","getCacheDir","join","getCacheDir","readFile","mkdir","writeFile","METRIC_SET_METRICS","allVitalsUnknown","execFile"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/output.ts","../src/plugins.ts","../src/commands/apps.ts","../src/commands/releases.ts","../src/utils/file-validation.ts","../src/utils/bcp47.ts","../src/utils/image-validation.ts","../src/utils/fastlane.ts","../src/utils/listing-text.ts","../src/commands/listings.ts","../src/commands/migrate.ts","../src/utils/validation.ts","../src/utils/release-notes.ts","../src/commands/validate.ts","../src/commands/publish.ts","../src/commands/reviews.ts","../src/utils/sentiment.ts","../src/commands/subscriptions.ts","../src/commands/vitals.ts","../src/commands/iap.ts","../src/commands/purchases.ts","../src/commands/pricing.ts","../src/commands/reports.ts","../src/commands/users.ts","../src/commands/grants.ts","../src/commands/testers.ts","../src/utils/git-notes.ts","../src/commands/app-recovery.ts","../src/commands/data-safety.ts","../src/commands/external-transactions.ts","../src/commands/device-tiers.ts","../src/commands/one-time-products.ts","../src/utils/spinner.ts","../src/utils/train-state.ts","../src/commands/train.ts","../src/commands/games.ts","../src/commands/enterprise.ts","../src/audit.ts","../src/commands/quota.ts","../src/utils/safe-path.ts","../src/commands/init.ts","../src/preflight/types.ts","../src/preflight/config.ts","../src/preflight/aab-reader.ts","../src/preflight/manifest-parser.ts","../src/preflight/scanners/manifest-scanner.ts","../src/preflight/scanners/permissions-scanner.ts","../src/preflight/scanners/native-libs-scanner.ts","../src/preflight/scanners/metadata-scanner.ts","../src/preflight/scanners/secrets-scanner.ts","../src/preflight/scan-files.ts","../src/preflight/scanners/billing-scanner.ts","../src/preflight/scanners/privacy-scanner.ts","../src/preflight/scanners/policy-scanner.ts","../src/preflight/scanners/size-scanner.ts","../src/preflight/orchestrator.ts","../src/utils/sort.ts","../src/commands/plugin-scaffold.ts","../src/utils/webhooks.ts","../src/commands/internal-sharing.ts","../src/commands/generated-apks.ts","../src/commands/purchase-options.ts","../src/commands/bundle-analysis.ts","../src/commands/status.ts","../src/commands/changelog.ts","../src/commands/rtdn.ts"],"sourcesContent":["export class GpcError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly exitCode: number,\n public readonly suggestion?: string,\n ) {\n super(message);\n this.name = \"GpcError\";\n }\n\n toJSON() {\n return {\n success: false,\n error: {\n code: this.code,\n message: this.message,\n suggestion: this.suggestion,\n },\n };\n }\n}\n\nexport class ConfigError extends GpcError {\n constructor(message: string, code: string, suggestion?: string) {\n super(message, code, 1, suggestion);\n this.name = \"ConfigError\";\n }\n}\n\nexport class ApiError extends GpcError {\n constructor(\n message: string,\n code: string,\n public readonly statusCode?: number,\n suggestion?: string,\n ) {\n super(message, code, 4, suggestion);\n this.name = \"ApiError\";\n }\n}\n\nexport class NetworkError extends GpcError {\n constructor(message: string, suggestion?: string) {\n super(message, \"NETWORK_ERROR\", 5, suggestion);\n this.name = \"NetworkError\";\n }\n}\n","import type { OutputFormat } from \"@gpc-cli/config\";\nimport process from \"node:process\";\n\n// Minimal color helpers (no external dep, respects NO_COLOR / FORCE_COLOR)\nfunction isColorEnabled(): boolean {\n if (process.env[\"NO_COLOR\"] !== undefined && process.env[\"NO_COLOR\"] !== \"\") return false;\n const fc = process.env[\"FORCE_COLOR\"];\n if (fc === \"1\" || fc === \"2\" || fc === \"3\") return true;\n return process.stdout.isTTY ?? false;\n}\nfunction ansi(code: number, s: string): string {\n return isColorEnabled() ? `\\x1b[${code}m${s}\\x1b[0m` : s;\n}\nfunction bold(s: string): string {\n return ansi(1, s);\n}\nfunction dim(s: string): string {\n return ansi(2, s);\n}\n\nexport function detectOutputFormat(): OutputFormat {\n return process.stdout.isTTY ? \"table\" : \"json\";\n}\n\nexport function formatOutput(data: unknown, format: OutputFormat, redact = true): string {\n const safe = redact ? redactSensitive(data) : data;\n switch (format) {\n case \"json\":\n return formatJson(safe);\n case \"yaml\":\n return formatYaml(safe);\n case \"markdown\":\n return formatMarkdown(safe);\n case \"table\":\n return formatTable(safe);\n case \"junit\":\n return formatJunit(safe);\n default:\n return formatJson(safe);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Sensitive field redaction\n// ---------------------------------------------------------------------------\n\nexport const SENSITIVE_KEYS = new Set([\n \"private_key\",\n \"privateKey\",\n \"private_key_id\",\n \"privateKeyId\",\n \"accessToken\",\n \"access_token\",\n \"refreshToken\",\n \"refresh_token\",\n \"client_secret\",\n \"clientSecret\",\n \"token\",\n \"password\",\n \"secret\",\n \"credentials\",\n \"keyFile\",\n \"key_file\",\n \"serviceAccount\",\n \"service-account\",\n \"apiKey\",\n \"api_key\",\n \"auth_token\",\n \"bearer\",\n \"jwt\",\n \"signing_key\",\n \"keystore_password\",\n \"store_password\",\n \"key_password\",\n]);\n\nconst REDACTED = \"[REDACTED]\";\n\n/** Recursively redact sensitive fields from data before output. */\nexport function redactSensitive(data: unknown): unknown {\n if (data === null || data === undefined) return data;\n\n if (typeof data === \"string\") return data;\n if (typeof data === \"number\" || typeof data === \"boolean\") return data;\n\n if (Array.isArray(data)) {\n return data.map((item) => redactSensitive(item));\n }\n\n if (typeof data === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data as Record<string, unknown>)) {\n if (SENSITIVE_KEYS.has(key)) {\n result[key] = REDACTED;\n } else {\n result[key] = redactSensitive(value);\n }\n }\n return result;\n }\n\n return data;\n}\n\nfunction formatJson(data: unknown): string {\n return JSON.stringify(data, null, 2);\n}\n\nfunction formatYaml(data: unknown, indent = 0): string {\n if (data === null || data === undefined) {\n return \"null\";\n }\n\n if (typeof data === \"string\") {\n return data.includes(\"\\n\")\n ? `|\\n${data\n .split(\"\\n\")\n .map((l) => `${\" \".repeat(indent + 1)}${l}`)\n .join(\"\\n\")}`\n : data;\n }\n\n if (typeof data === \"number\" || typeof data === \"boolean\") {\n return String(data);\n }\n\n if (Array.isArray(data)) {\n if (data.length === 0) return \"[]\";\n return data\n .map((item) => {\n const value = formatYaml(item, indent + 1);\n const prefix = `${\" \".repeat(indent)}- `;\n if (typeof item === \"object\" && item !== null && !Array.isArray(item)) {\n const lines = value.split(\"\\n\");\n return `${prefix}${lines[0]}\\n${lines\n .slice(1)\n .map((l) => `${\" \".repeat(indent)} ${l}`)\n .join(\"\\n\")}`;\n }\n return `${prefix}${value}`;\n })\n .join(\"\\n\");\n }\n\n if (typeof data === \"object\") {\n const entries = Object.entries(data as Record<string, unknown>);\n if (entries.length === 0) return \"{}\";\n return entries\n .map(([key, value]) => {\n if (typeof value === \"object\" && value !== null) {\n return `${\" \".repeat(indent)}${key}:\\n${formatYaml(value, indent + 1)}`;\n }\n return `${\" \".repeat(indent)}${key}: ${formatYaml(value, indent)}`;\n })\n .join(\"\\n\");\n }\n\n return String(data);\n}\n\nconst DEFAULT_CELL_WIDTH = 60;\n\nfunction computeMaxCellWidth(colCount: number): number {\n const cols = process.stdout.columns;\n if (cols && colCount > 0) {\n return Math.max(20, Math.floor(cols / colCount) - 2);\n }\n return DEFAULT_CELL_WIDTH;\n}\n\nfunction truncateCell(value: string, maxWidth = DEFAULT_CELL_WIDTH): string {\n if (value.length <= maxWidth) return value;\n return value.slice(0, maxWidth - 3) + \"...\";\n}\n\nfunction isNumericCell(value: string): boolean {\n return /^-?\\d[\\d,]*(\\.\\d+)?%?$/.test(value.trim());\n}\n\nfunction cellValue(val: unknown): string {\n if (val === null || val === undefined) return \"\";\n if (typeof val === \"object\") {\n if (Array.isArray(val)) return val.length === 0 ? \"\" : JSON.stringify(val);\n return JSON.stringify(val);\n }\n return String(val);\n}\n\nfunction formatTable(data: unknown): string {\n const rows = toRows(data);\n if (rows.length === 0) return \"\";\n\n const firstRow = rows[0];\n if (!firstRow) return \"\";\n const keys = Object.keys(firstRow);\n if (keys.length === 0) return \"\";\n\n const colCount = keys.length;\n const maxCellWidth = computeMaxCellWidth(colCount);\n\n const widths = keys.map((key) =>\n Math.max(\n key.length,\n ...rows.map((row) => truncateCell(cellValue(row[key]), maxCellWidth).length),\n ),\n );\n\n // Detect numeric columns (right-align numbers)\n const isNumeric = keys.map((key) =>\n rows.every((row) => {\n const v = cellValue(row[key]);\n return v === \"\" || isNumericCell(v);\n }),\n );\n\n const header = keys.map((key, i) => bold(key.padEnd(widths[i] ?? 0))).join(\" \");\n const separator = widths.map((w) => dim(\"─\".repeat(w))).join(\" \");\n const body = rows\n .map((row) =>\n keys\n .map((key, i) => {\n const cell = truncateCell(cellValue(row[key]), maxCellWidth);\n const w = widths[i] ?? 0;\n return isNumeric[i] ? cell.padStart(w) : cell.padEnd(w);\n })\n .join(\" \"),\n )\n .join(\"\\n\");\n\n return `${header}\\n${separator}\\n${body}`;\n}\n\nfunction formatMarkdown(data: unknown): string {\n const rows = toRows(data);\n if (rows.length === 0) return \"\";\n\n const firstRow = rows[0];\n if (!firstRow) return \"\";\n const keys = Object.keys(firstRow);\n if (keys.length === 0) return \"\";\n\n const widths = keys.map((key) =>\n Math.max(key.length, ...rows.map((row) => truncateCell(cellValue(row[key])).length)),\n );\n\n const header = `| ${keys.map((key, i) => key.padEnd(widths[i] ?? 0)).join(\" | \")} |`;\n const separator = `| ${widths.map((w) => \"-\".repeat(w)).join(\" | \")} |`;\n const body = rows\n .map(\n (row) =>\n `| ${keys.map((key, i) => truncateCell(cellValue(row[key])).padEnd(widths[i] ?? 0)).join(\" | \")} |`,\n )\n .join(\"\\n\");\n\n return `${header}\\n${separator}\\n${body}`;\n}\n\nfunction toRows(data: unknown): Record<string, unknown>[] {\n if (Array.isArray(data)) {\n return data.filter(\n (item): item is Record<string, unknown> => typeof item === \"object\" && item !== null,\n );\n }\n if (typeof data === \"object\" && data !== null) {\n return [data as Record<string, unknown>];\n }\n return [];\n}\n\n// ---------------------------------------------------------------------------\n// JUnit XML output\n// ---------------------------------------------------------------------------\n\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\nfunction toTestCases(data: unknown, commandName: string): { cases: string[]; failures: number } {\n const cases: string[] = [];\n let failures = 0;\n\n if (Array.isArray(data)) {\n for (let i = 0; i < data.length; i++) {\n const tc = buildTestCase(data[i], commandName, i);\n cases.push(tc.xml);\n if (tc.failed) failures++;\n }\n } else if (typeof data === \"object\" && data !== null) {\n const tc = buildTestCase(data, commandName);\n cases.push(tc.xml);\n if (tc.failed) failures++;\n } else if (typeof data === \"string\") {\n cases.push(\n ` <testcase name=\"${escapeXml(data)}\" classname=\"gpc.${escapeXml(commandName)}\" />`,\n );\n }\n\n return { cases, failures };\n}\n\nfunction buildTestCase(\n item: unknown,\n commandName: string,\n index = 0,\n): { xml: string; failed: boolean } {\n if (typeof item !== \"object\" || item === null) {\n const text = String(item);\n return {\n xml: ` <testcase name=\"${escapeXml(text)}\" classname=\"gpc.${escapeXml(commandName)}\" />`,\n failed: false,\n };\n }\n\n const record = item as Record<string, unknown>;\n\n // Pick the first meaningful identifier, skipping sentinel dash/empty values\n // that commands use as display placeholders (e.g. `name: s[\"name\"] || \"-\"`).\n const CANDIDATE_KEYS = [\n \"name\",\n \"title\",\n \"sku\",\n \"id\",\n \"reviewId\",\n \"productId\",\n \"packageName\",\n \"track\",\n \"trackId\",\n \"versionCode\",\n \"region\",\n \"languageCode\",\n ] as const;\n let resolvedName = `item-${index + 1}`;\n for (const key of CANDIDATE_KEYS) {\n const val = record[key];\n if (val != null && val !== \"\" && val !== \"-\") {\n resolvedName = String(val);\n break;\n }\n }\n const name = escapeXml(resolvedName);\n const classname = `gpc.${escapeXml(commandName)}`;\n\n // Detect threshold breach (vitals)\n const breached = record[\"breached\"];\n if (breached === true) {\n const message = escapeXml(String(record[\"message\"] ?? \"threshold breached\"));\n const details = escapeXml(\n String(record[\"details\"] ?? record[\"metric\"] ?? JSON.stringify(item)),\n );\n return {\n xml: ` <testcase name=\"${name}\" classname=\"${classname}\">\\n <failure message=\"${message}\">${details}</failure>\\n </testcase>`,\n failed: true,\n };\n }\n\n return {\n xml: ` <testcase name=\"${name}\" classname=\"${classname}\" />`,\n failed: false,\n };\n}\n\n/**\n * Auto-pipe `output` to `$PAGER` when:\n * - stdout is a TTY\n * - row count exceeds terminal height\n * - a pager is available in the environment\n *\n * Falls back to `console.log(output)` when pagination is not applicable.\n */\nexport async function maybePaginate(output: string): Promise<void> {\n const isTTY = process.stdout.isTTY;\n const termHeight = process.stdout.rows ?? 24;\n const lineCount = output.split(\"\\n\").length;\n\n if (!isTTY || lineCount <= termHeight) {\n console.log(output);\n return;\n }\n\n const pager = process.env[\"GPC_PAGER\"] ?? process.env[\"PAGER\"] ?? \"less\";\n\n try {\n const { spawn } = await import(\"node:child_process\");\n const child = spawn(pager, [], {\n stdio: [\"pipe\", \"inherit\", \"inherit\"],\n env: { ...process.env, LESS: process.env[\"LESS\"] ?? \"-FRX\" },\n });\n child.stdin.write(output);\n child.stdin.end();\n await new Promise<void>((resolve) => child.on(\"close\", resolve));\n } catch {\n // Pager not available — fall back to plain output\n console.log(output);\n }\n}\n\nexport function formatJunit(data: unknown, commandName = \"command\"): string {\n const { cases, failures } = toTestCases(data, commandName);\n const tests = cases.length;\n\n const lines = [\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>',\n `<testsuites name=\"gpc\" tests=\"${tests}\" failures=\"${failures}\" time=\"0\">`,\n ` <testsuite name=\"${escapeXml(commandName)}\" tests=\"${tests}\" failures=\"${failures}\">`,\n ...cases,\n \" </testsuite>\",\n \"</testsuites>\",\n ];\n\n return lines.join(\"\\n\");\n}\n","import type {\n GpcPlugin,\n PluginHooks,\n BeforeCommandHandler,\n AfterCommandHandler,\n ErrorHandler,\n BeforeRequestHandler,\n AfterResponseHandler,\n CommandEvent,\n CommandResult,\n PluginError,\n PluginCommand,\n PluginManifest,\n PluginPermission,\n RequestEvent,\n ResponseEvent,\n} from \"@gpc-cli/plugin-sdk\";\nimport { GpcError } from \"./errors.js\";\n\n// ---------------------------------------------------------------------------\n// Plugin Manager — orchestrates discovery, loading, and lifecycle\n// ---------------------------------------------------------------------------\n\nconst FIRST_PARTY_PLUGINS = new Set([\n \"@gpc-cli/plugin-ci\",\n \"@gpc-cli/plugin-sdk\",\n]);\n\nexport class PluginManager {\n private plugins: LoadedPlugin[] = [];\n private beforeHandlers: BeforeCommandHandler[] = [];\n private afterHandlers: AfterCommandHandler[] = [];\n private errorHandlers: ErrorHandler[] = [];\n private beforeRequestHandlers: BeforeRequestHandler[] = [];\n private afterResponseHandlers: AfterResponseHandler[] = [];\n private registeredCommands: PluginCommand[] = [];\n\n /** Load and register a plugin */\n async load(plugin: GpcPlugin, manifest?: PluginManifest): Promise<void> {\n const isTrusted = manifest?.trusted ?? FIRST_PARTY_PLUGINS.has(plugin.name);\n\n if (!isTrusted && manifest?.permissions) {\n validatePermissions(manifest.permissions);\n }\n\n const hooks = createHooks(\n this.beforeHandlers,\n this.afterHandlers,\n this.errorHandlers,\n this.beforeRequestHandlers,\n this.afterResponseHandlers,\n this.registeredCommands,\n );\n\n await plugin.register(hooks);\n\n this.plugins.push({\n name: plugin.name,\n version: plugin.version,\n trusted: isTrusted,\n });\n }\n\n /** Run all beforeCommand handlers */\n async runBeforeCommand(event: CommandEvent): Promise<void> {\n for (const handler of this.beforeHandlers) {\n await handler(event);\n }\n }\n\n /** Run all afterCommand handlers */\n async runAfterCommand(event: CommandEvent, result: CommandResult): Promise<void> {\n for (const handler of this.afterHandlers) {\n await handler(event, result);\n }\n }\n\n /** Run all onError handlers */\n async runOnError(event: CommandEvent, error: PluginError): Promise<void> {\n for (const handler of this.errorHandlers) {\n try {\n await handler(event, error);\n } catch {\n // Don't let error handlers crash the process\n }\n }\n }\n\n /** Run all beforeRequest handlers */\n async runBeforeRequest(event: RequestEvent): Promise<void> {\n for (const handler of this.beforeRequestHandlers) {\n try {\n await handler(event);\n } catch {\n // Don't let request hooks block API calls\n }\n }\n }\n\n /** Run all afterResponse handlers */\n async runAfterResponse(event: RequestEvent, response: ResponseEvent): Promise<void> {\n for (const handler of this.afterResponseHandlers) {\n try {\n await handler(event, response);\n } catch {\n // Don't let response hooks crash the process\n }\n }\n }\n\n /** Get commands registered by plugins */\n getRegisteredCommands(): PluginCommand[] {\n return [...this.registeredCommands];\n }\n\n /** Get list of loaded plugins */\n getLoadedPlugins(): LoadedPlugin[] {\n return [...this.plugins];\n }\n\n /** Whether any request/response hooks are registered */\n hasRequestHooks(): boolean {\n return this.beforeRequestHandlers.length > 0 || this.afterResponseHandlers.length > 0;\n }\n\n /** Reset (for testing) */\n reset(): void {\n this.plugins = [];\n this.beforeHandlers = [];\n this.afterHandlers = [];\n this.errorHandlers = [];\n this.beforeRequestHandlers = [];\n this.afterResponseHandlers = [];\n this.registeredCommands = [];\n }\n}\n\nexport interface LoadedPlugin {\n name: string;\n version: string;\n trusted: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Hook factory\n// ---------------------------------------------------------------------------\n\nfunction createHooks(\n beforeHandlers: BeforeCommandHandler[],\n afterHandlers: AfterCommandHandler[],\n errorHandlers: ErrorHandler[],\n beforeRequestHandlers: BeforeRequestHandler[],\n afterResponseHandlers: AfterResponseHandler[],\n registeredCommands: PluginCommand[],\n): PluginHooks {\n return {\n beforeCommand(handler) {\n beforeHandlers.push(handler);\n },\n afterCommand(handler) {\n afterHandlers.push(handler);\n },\n onError(handler) {\n errorHandlers.push(handler);\n },\n beforeRequest(handler) {\n beforeRequestHandlers.push(handler);\n },\n afterResponse(handler) {\n afterResponseHandlers.push(handler);\n },\n registerCommands(registrar) {\n const registry = {\n add(cmd: PluginCommand) {\n registeredCommands.push(cmd);\n },\n };\n registrar(registry);\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Permission validation\n// ---------------------------------------------------------------------------\n\nconst VALID_PERMISSIONS: ReadonlySet<string> = new Set<PluginPermission>([\n \"read:config\",\n \"write:config\",\n \"read:auth\",\n \"api:read\",\n \"api:write\",\n \"commands:register\",\n \"hooks:beforeCommand\",\n \"hooks:afterCommand\",\n \"hooks:onError\",\n \"hooks:beforeRequest\",\n \"hooks:afterResponse\",\n]);\n\nfunction validatePermissions(permissions: PluginPermission[]): void {\n for (const perm of permissions) {\n if (!VALID_PERMISSIONS.has(perm)) {\n throw new GpcError(\n `Unknown plugin permission: \"${perm}\"`,\n \"PLUGIN_INVALID_PERMISSION\",\n 10,\n `Valid permissions: ${[...VALID_PERMISSIONS].join(\", \")}`,\n );\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Plugin discovery\n// ---------------------------------------------------------------------------\n\nexport interface DiscoverPluginsOptions {\n /** Plugin names from config file */\n configPlugins?: string[];\n\n /** Working directory for node_modules scanning */\n cwd?: string;\n}\n\n/**\n * Discover plugins from multiple sources:\n * 1. Explicit config: gpc.config.ts → plugins: [...]\n * 2. Convention: node_modules/@gpc-cli/plugin-*\n * 3. Convention: node_modules/gpc-plugin-*\n */\nexport async function discoverPlugins(options?: DiscoverPluginsOptions): Promise<GpcPlugin[]> {\n const plugins: GpcPlugin[] = [];\n const seen = new Set<string>();\n\n // Source 1: Explicit config plugins\n if (options?.configPlugins) {\n for (const name of options.configPlugins) {\n if (seen.has(name)) continue;\n try {\n const mod = await import(name);\n const plugin = resolvePlugin(mod);\n if (plugin) {\n plugins.push(plugin);\n seen.add(name);\n }\n } catch {\n // Plugin not found — skip silently\n }\n }\n }\n\n return plugins;\n}\n\n/**\n * Resolve a plugin from a module.\n * Supports: default export, named `plugin` export, or the module itself as a plugin.\n */\nfunction resolvePlugin(mod: unknown): GpcPlugin | undefined {\n if (!mod || typeof mod !== \"object\") return undefined;\n\n const m = mod as Record<string, unknown>;\n\n // Check default export\n if (isPlugin(m[\"default\"])) return m[\"default\"];\n\n // Check named `plugin` export\n if (isPlugin(m[\"plugin\"])) return m[\"plugin\"];\n\n // Check if module itself is a plugin\n if (isPlugin(m)) return m as unknown as GpcPlugin;\n\n return undefined;\n}\n\nfunction isPlugin(obj: unknown): obj is GpcPlugin {\n if (!obj || typeof obj !== \"object\") return false;\n const p = obj as Record<string, unknown>;\n return (\n typeof p[\"name\"] === \"string\" &&\n typeof p[\"version\"] === \"string\" &&\n typeof p[\"register\"] === \"function\"\n );\n}\n","import type { PlayApiClient } from \"@gpc-cli/api\";\n\nexport interface AppInfo {\n packageName: string;\n title?: string;\n defaultLanguage?: string;\n contactEmail?: string;\n}\n\nexport async function getAppInfo(client: PlayApiClient, packageName: string): Promise<AppInfo> {\n // Create an edit to read app details (Google Play requires an edit context)\n const edit = await client.edits.insert(packageName);\n try {\n const details = await client.details.get(packageName, edit.id);\n // Delete the edit since we're only reading\n await client.edits.delete(packageName, edit.id);\n return {\n packageName,\n title: details.title,\n defaultLanguage: details.defaultLanguage,\n contactEmail: details.contactEmail,\n };\n } catch (error) {\n // Clean up edit on failure\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n","import { stat } from \"node:fs/promises\";\nimport { extname } from \"node:path\";\nimport type {\n PlayApiClient,\n Release,\n Track,\n ExternallyHostedApk,\n ExternallyHostedApkResponse,\n UploadProgressEvent,\n ResumableUploadOptions,\n} from \"@gpc-cli/api\";\nimport type { AppEdit } from \"@gpc-cli/api\";\nimport { PlayApiError } from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\nimport { validateUploadFile } from \"../utils/file-validation.js\";\n\n/**\n * Retry an edit-based operation once if it fails with 409 Conflict (stale edit).\n * Automatically discards the stale edit and creates a fresh one on retry.\n */\nasync function withRetryOnConflict<T>(\n client: PlayApiClient,\n packageName: string,\n operation: (edit: AppEdit) => Promise<T>,\n): Promise<T> {\n const edit = await client.edits.insert(packageName);\n try {\n return await operation(edit);\n } catch (error) {\n const isConflict = error instanceof PlayApiError && error.statusCode === 409;\n if (!isConflict) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n // Discard stale edit, retry with fresh one\n await client.edits.delete(packageName, edit.id).catch(() => {});\n const freshEdit = await client.edits.insert(packageName);\n try {\n return await operation(freshEdit);\n } catch (retryError) {\n await client.edits.delete(packageName, freshEdit.id).catch(() => {});\n throw retryError;\n }\n }\n}\n\n/** Warn if edit is within 5 minutes of expiry. */\nlet _consoleEditWarningShown = false;\nfunction warnAboutConcurrentEdits(): void {\n if (_consoleEditWarningShown) return;\n _consoleEditWarningShown = true;\n process.emitWarning?.(\n \"If the Play Console has pending changes, they may be discarded when this edit is committed. \" +\n \"Avoid making changes in the Play Console while CLI operations are in progress.\",\n \"ConcurrentEditWarning\",\n );\n}\n\nfunction warnIfEditExpiring(edit: AppEdit): void {\n if (!edit.expiryTimeSeconds) return;\n const expiryMs = Number(edit.expiryTimeSeconds) * 1000;\n const remainingMs = expiryMs - Date.now();\n if (remainingMs < 5 * 60 * 1000 && remainingMs > 0) {\n const minutes = Math.round(remainingMs / 60_000);\n process.emitWarning?.(\n `Edit session expires in ~${minutes} minute${minutes !== 1 ? \"s\" : \"\"}. Long uploads may fail. Consider starting a fresh operation.`,\n \"EditExpiryWarning\",\n );\n }\n}\n\n/**\n * Run an edit-lifecycle operation with automatic retry on expired-edit errors.\n * If the API returns API_EDIT_EXPIRED (FAILED_PRECONDITION), the helper opens a\n * fresh edit and retries the operation exactly once.\n */\nexport async function withFreshEdit<T>(\n client: PlayApiClient,\n packageName: string,\n operation: (editId: string) => Promise<T>,\n): Promise<T> {\n const edit = await client.edits.insert(packageName);\n try {\n return await operation(edit.id);\n } catch (error) {\n if (error instanceof PlayApiError && error.code === \"API_EDIT_EXPIRED\") {\n // Discard stale edit (best effort) and retry with a fresh one\n await client.edits.delete(packageName, edit.id).catch(() => {});\n const freshEdit = await client.edits.insert(packageName);\n try {\n return await operation(freshEdit.id);\n } catch (retryError) {\n await client.edits.delete(packageName, freshEdit.id).catch(() => {});\n throw retryError;\n }\n }\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport interface UploadResult {\n versionCode: number;\n track: string;\n status: string;\n}\n\nexport interface ReleaseStatusResult {\n track: string;\n status: string;\n versionCodes: string[];\n userFraction?: number;\n releaseNotes?: { language: string; text: string }[];\n}\n\nexport interface DryRunUploadResult {\n dryRun: true;\n file: { path: string; valid: boolean; errors: string[]; warnings: string[] };\n track: string;\n currentReleases: { versionCodes: string[]; status: string; userFraction?: number }[];\n plannedRelease: { status: string; userFraction?: number };\n}\n\nexport async function uploadRelease(\n client: PlayApiClient,\n packageName: string,\n filePath: string,\n options: {\n track: string;\n status?: string;\n userFraction?: number;\n releaseNotes?: { language: string; text: string }[];\n releaseName?: string;\n mappingFile?: string;\n dryRun?: boolean;\n onProgress?: (uploaded: number, total: number) => void;\n onUploadProgress?: (event: UploadProgressEvent) => void;\n uploadOptions?: Pick<\n ResumableUploadOptions,\n \"chunkSize\" | \"resumeSessionUri\" | \"maxResumeAttempts\"\n >;\n },\n): Promise<UploadResult | DryRunUploadResult> {\n // Validate file before upload\n const validation = await validateUploadFile(filePath);\n\n if (options.dryRun) {\n const plannedStatus = options.status || (options.userFraction ? \"inProgress\" : \"completed\");\n\n // Fetch current track state without modifying anything\n let currentReleases: DryRunUploadResult[\"currentReleases\"] = [];\n const edit = await client.edits.insert(packageName);\n try {\n const trackData = await client.tracks.get(packageName, edit.id, options.track);\n currentReleases = (trackData.releases || []).map((r) => ({\n versionCodes: r.versionCodes || [],\n status: r.status,\n ...(r.userFraction !== undefined && { userFraction: r.userFraction }),\n }));\n } catch {\n // Track may not exist yet — that's fine for dry-run\n } finally {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n }\n\n return {\n dryRun: true,\n file: {\n path: filePath,\n valid: validation.valid,\n errors: validation.errors,\n warnings: validation.warnings,\n },\n track: options.track,\n currentReleases,\n plannedRelease: {\n status: plannedStatus,\n ...(options.userFraction !== undefined && { userFraction: options.userFraction }),\n },\n };\n }\n\n if (!validation.valid) {\n throw new GpcError(\n `File validation failed:\\n${validation.errors.join(\"\\n\")}`,\n \"RELEASE_INVALID_FILE\",\n 2,\n \"Check that the file is a valid AAB or APK and is not corrupted.\",\n );\n }\n\n // Get file size for progress reporting\n let fileSize = 0;\n try {\n const { size } = await stat(filePath);\n fileSize = size;\n } catch {\n /* ignore — file was validated above */\n }\n\n if (options.onProgress) options.onProgress(0, fileSize);\n\n const edit = await client.edits.insert(packageName);\n warnIfEditExpiring(edit);\n warnAboutConcurrentEdits();\n try {\n // Upload AAB or APK via the appropriate endpoint\n const isApk = extname(filePath).toLowerCase() === \".apk\";\n const uploadOpts = {\n ...options.uploadOptions,\n onProgress: (event: UploadProgressEvent) => {\n if (options.onProgress) options.onProgress(event.bytesUploaded, event.totalBytes);\n if (options.onUploadProgress) options.onUploadProgress(event);\n },\n };\n const bundle = isApk\n ? await client.apks.upload(packageName, edit.id, filePath, uploadOpts)\n : await client.bundles.upload(packageName, edit.id, filePath, uploadOpts);\n\n // Upload mapping file if provided\n if (options.mappingFile) {\n await client.deobfuscation.upload(\n packageName,\n edit.id,\n bundle.versionCode,\n options.mappingFile,\n );\n }\n\n // Create release and assign to track\n const release: Release = {\n versionCodes: [String(bundle.versionCode)],\n status: (options.status ||\n (options.userFraction ? \"inProgress\" : \"completed\")) as Release[\"status\"],\n ...(options.userFraction && { userFraction: options.userFraction }),\n ...(options.releaseNotes && { releaseNotes: options.releaseNotes }),\n ...(options.releaseName && { name: options.releaseName }),\n };\n\n await client.tracks.update(packageName, edit.id, options.track, release);\n\n // Validate and commit\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n\n return {\n versionCode: bundle.versionCode,\n track: options.track,\n status: release.status,\n };\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function getReleasesStatus(\n client: PlayApiClient,\n packageName: string,\n trackFilter?: string,\n): Promise<ReleaseStatusResult[]> {\n const edit = await client.edits.insert(packageName);\n try {\n const tracks = trackFilter\n ? [await client.tracks.get(packageName, edit.id, trackFilter)]\n : await client.tracks.list(packageName, edit.id);\n\n await client.edits.delete(packageName, edit.id);\n\n const results: ReleaseStatusResult[] = [];\n for (const track of tracks) {\n for (const release of track.releases || []) {\n results.push({\n track: track.track,\n status: release.status,\n versionCodes: release.versionCodes || [],\n userFraction: release.userFraction,\n releaseNotes: release.releaseNotes,\n });\n }\n }\n return results;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function promoteRelease(\n client: PlayApiClient,\n packageName: string,\n fromTrack: string,\n toTrack: string,\n options?: { status?: string; userFraction?: number; releaseNotes?: { language: string; text: string }[] },\n): Promise<ReleaseStatusResult> {\n // Validate inputs before opening an edit\n if (options?.userFraction && (options.userFraction <= 0 || options.userFraction > 1)) {\n throw new GpcError(\n \"Rollout percentage must be between 0 and 1 (e.g., 0.1 for 10%)\",\n \"RELEASE_INVALID_FRACTION\",\n 2,\n \"Use a decimal value like 0.1 for 10%, 0.5 for 50%, or 1.0 for 100%.\",\n );\n }\n\n return withRetryOnConflict(client, packageName, async (edit) => {\n // Get current release from source track\n const sourceTrack = await client.tracks.get(packageName, edit.id, fromTrack);\n const currentRelease = sourceTrack.releases?.find(\n (r) => r.status === \"completed\" || r.status === \"inProgress\",\n );\n\n if (!currentRelease) {\n throw new GpcError(\n `No active release found on track \"${fromTrack}\"`,\n \"RELEASE_NOT_FOUND\",\n 1,\n `Ensure there is a completed or in-progress release on the \"${fromTrack}\" track before promoting.`,\n );\n }\n\n const release: Release = {\n versionCodes: currentRelease.versionCodes,\n status: (options?.status || (options?.userFraction ? \"inProgress\" : \"completed\")) as Release[\"status\"],\n ...(options?.userFraction && { userFraction: options.userFraction }),\n releaseNotes: options?.releaseNotes || currentRelease.releaseNotes || [],\n };\n\n await client.tracks.update(packageName, edit.id, toTrack, release);\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n\n return {\n track: toTrack,\n status: release.status,\n versionCodes: release.versionCodes,\n userFraction: release.userFraction,\n };\n });\n}\n\nexport async function updateRollout(\n client: PlayApiClient,\n packageName: string,\n track: string,\n action: \"increase\" | \"halt\" | \"resume\" | \"complete\",\n userFraction?: number,\n): Promise<ReleaseStatusResult> {\n const edit = await client.edits.insert(packageName);\n try {\n const trackData = await client.tracks.get(packageName, edit.id, track);\n const currentRelease = trackData.releases?.find(\n (r) => r.status === \"inProgress\" || r.status === \"halted\",\n );\n\n if (!currentRelease) {\n throw new GpcError(\n `No active rollout found on track \"${track}\"`,\n \"ROLLOUT_NOT_FOUND\",\n 1,\n `There is no in-progress or halted rollout on the \"${track}\" track. Start a staged rollout first with: gpc releases upload --track ${track} --status inProgress --fraction 0.1`,\n );\n }\n\n let newStatus: string;\n let newFraction: number | undefined;\n\n switch (action) {\n case \"increase\":\n if (!userFraction)\n throw new GpcError(\n \"--to <percentage> is required for rollout increase\",\n \"ROLLOUT_MISSING_FRACTION\",\n 2,\n \"Specify the target rollout percentage with --to, e.g.: gpc rollout increase --to 0.5\",\n );\n if (userFraction <= 0 || userFraction > 1) {\n throw new GpcError(\n \"Rollout percentage must be between 0 and 1 (e.g., 0.1 for 10%)\",\n \"RELEASE_INVALID_FRACTION\",\n 2,\n \"Use a decimal value like 0.1 for 10%, 0.5 for 50%, or 1.0 for 100%.\",\n );\n }\n newStatus = \"inProgress\";\n newFraction = userFraction;\n break;\n case \"halt\":\n newStatus = \"halted\";\n newFraction = currentRelease.userFraction;\n break;\n case \"resume\":\n newStatus = \"inProgress\";\n newFraction = currentRelease.userFraction;\n break;\n case \"complete\":\n newStatus = \"completed\";\n newFraction = undefined;\n break;\n }\n\n const release: Release = {\n versionCodes: currentRelease.versionCodes,\n status: newStatus as Release[\"status\"],\n ...(newFraction !== undefined && { userFraction: newFraction }),\n releaseNotes: currentRelease.releaseNotes || [],\n };\n\n await client.tracks.update(packageName, edit.id, track, release);\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n\n return {\n track,\n status: newStatus,\n versionCodes: release.versionCodes,\n userFraction: newFraction,\n };\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function listTracks(client: PlayApiClient, packageName: string): Promise<Track[]> {\n const edit = await client.edits.insert(packageName);\n try {\n const tracks = await client.tracks.list(packageName, edit.id);\n await client.edits.delete(packageName, edit.id);\n return tracks;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function createTrack(\n client: PlayApiClient,\n packageName: string,\n trackName: string,\n): Promise<Track> {\n if (!trackName || trackName.trim().length === 0) {\n throw new GpcError(\n \"Track name must not be empty\",\n \"TRACK_INVALID_NAME\",\n 2,\n \"Provide a valid custom track name, e.g.: gpc tracks create my-qa-track\",\n );\n }\n\n const edit = await client.edits.insert(packageName);\n try {\n const track = await client.tracks.create(packageName, edit.id, trackName);\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n return track;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function updateTrackConfig(\n client: PlayApiClient,\n packageName: string,\n trackName: string,\n config: Record<string, unknown>,\n): Promise<Track> {\n if (!trackName || trackName.trim().length === 0) {\n throw new GpcError(\n \"Track name must not be empty\",\n \"TRACK_INVALID_NAME\",\n 2,\n \"Provide a valid track name.\",\n );\n }\n\n const edit = await client.edits.insert(packageName);\n try {\n const release: Release = {\n versionCodes: (config[\"versionCodes\"] as string[]) || [],\n status: ((config[\"status\"] as string) || \"completed\") as Release[\"status\"],\n };\n if (config[\"userFraction\"] !== undefined) {\n release.userFraction = config[\"userFraction\"] as number;\n }\n if (config[\"releaseNotes\"]) {\n release.releaseNotes = config[\"releaseNotes\"] as { language: string; text: string }[];\n }\n if (config[\"name\"]) {\n release.name = config[\"name\"] as string;\n }\n\n const track = await client.tracks.update(packageName, edit.id, trackName, release);\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n return track;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\n/**\n * Fetch release notes from the latest active release on a given track.\n * Opens and discards an edit — read-only, no mutations.\n */\nexport async function fetchReleaseNotes(\n client: PlayApiClient,\n packageName: string,\n track: string,\n): Promise<{ language: string; text: string }[]> {\n const edit = await client.edits.insert(packageName);\n try {\n const trackData = await client.tracks.get(packageName, edit.id, track);\n const release =\n trackData.releases?.find((r) => r.status === \"completed\" || r.status === \"inProgress\") ??\n trackData.releases?.[0];\n\n if (!release) {\n throw new GpcError(\n `No release found on track \"${track}\" to copy notes from`,\n \"RELEASE_NOT_FOUND\",\n 1,\n `Ensure there is a release on the \"${track}\" track.`,\n );\n }\n\n return release.releaseNotes ?? [];\n } finally {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n }\n}\n\nexport interface ReleaseDiff {\n field: string;\n track1Value: string;\n track2Value: string;\n}\n\nexport async function diffReleases(\n client: PlayApiClient,\n packageName: string,\n fromTrack: string,\n toTrack: string,\n): Promise<{ fromTrack: string; toTrack: string; diffs: ReleaseDiff[] }> {\n const edit = await client.edits.insert(packageName);\n try {\n const [fromData, toData] = await Promise.all([\n client.tracks.get(packageName, edit.id, fromTrack),\n client.tracks.get(packageName, edit.id, toTrack),\n ]);\n await client.edits.delete(packageName, edit.id);\n\n const fromRelease = fromData.releases?.[0];\n const toRelease = toData.releases?.[0];\n const diffs: ReleaseDiff[] = [];\n\n const fields = [\"versionCodes\", \"status\", \"userFraction\", \"releaseNotes\", \"name\"] as const;\n for (const field of fields) {\n const v1 = fromRelease ? JSON.stringify(fromRelease[field] ?? null) : \"null\";\n const v2 = toRelease ? JSON.stringify(toRelease[field] ?? null) : \"null\";\n if (v1 !== v2) {\n diffs.push({ field, track1Value: v1, track2Value: v2 });\n }\n }\n\n return { fromTrack, toTrack, diffs };\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function uploadExternallyHosted(\n client: PlayApiClient,\n packageName: string,\n data: ExternallyHostedApk,\n): Promise<ExternallyHostedApkResponse> {\n if (!data.externallyHostedUrl) {\n throw new GpcError(\n \"externallyHostedUrl is required\",\n \"EXTERNAL_APK_MISSING_URL\",\n 2,\n \"Provide a valid URL for the externally hosted APK.\",\n );\n }\n\n if (!data.packageName) {\n throw new GpcError(\n \"packageName is required in externally hosted APK data\",\n \"EXTERNAL_APK_MISSING_PACKAGE\",\n 2,\n \"Include the packageName field in the APK configuration.\",\n );\n }\n\n const edit = await client.edits.insert(packageName);\n try {\n const result = await client.apks.addExternallyHosted(packageName, edit.id, data);\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n return result;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n","import { open, stat } from \"node:fs/promises\";\nimport { extname } from \"node:path\";\n\nexport interface FileValidationResult {\n valid: boolean;\n fileType: \"aab\" | \"apk\" | \"unknown\";\n sizeBytes: number;\n errors: string[];\n warnings: string[];\n}\n\n// ZIP magic bytes: PK\\x03\\x04\nconst ZIP_MAGIC = Buffer.from([0x50, 0x4b, 0x03, 0x04]);\n\nconst MAX_APK_SIZE = 1024 * 1024 * 1024; // 1 GB (Google Play API limit)\nconst MAX_AAB_SIZE = 2 * 1024 * 1024 * 1024; // 2 GB (Google Play API limit)\nconst LARGE_FILE_THRESHOLD = 100 * 1024 * 1024; // 100 MB — warn about upload time\n\nexport async function validateUploadFile(filePath: string): Promise<FileValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n // Check extension\n const ext = extname(filePath).toLowerCase();\n let fileType: FileValidationResult[\"fileType\"] = \"unknown\";\n\n if (ext === \".aab\") {\n fileType = \"aab\";\n } else if (ext === \".apk\") {\n fileType = \"apk\";\n } else {\n errors.push(`Unsupported file extension \"${ext}\". Expected .aab or .apk`);\n }\n\n // Check file exists and get size\n let sizeBytes: number;\n try {\n const stats = await stat(filePath);\n sizeBytes = stats.size;\n\n if (sizeBytes === 0) {\n errors.push(\"File is empty (0 bytes)\");\n }\n } catch {\n errors.push(`File not found: ${filePath}`);\n return { valid: false, fileType, sizeBytes: 0, errors, warnings };\n }\n\n // Check size limits\n if (fileType === \"apk\" && sizeBytes > MAX_APK_SIZE) {\n errors.push(\n `APK exceeds 1 GB limit (${formatSize(sizeBytes)}). Consider using AAB format instead.`,\n );\n }\n if (fileType === \"aab\" && sizeBytes > MAX_AAB_SIZE) {\n errors.push(`AAB exceeds 2 GB limit (${formatSize(sizeBytes)}).`);\n }\n\n if (sizeBytes > LARGE_FILE_THRESHOLD && errors.length === 0) {\n warnings.push(\n `Large file (${formatSize(sizeBytes)}). Upload may take a while on slow connections.`,\n );\n }\n\n // Check magic bytes — only read first 4 bytes, not the entire file\n if (sizeBytes > 0) {\n let fh;\n try {\n fh = await open(filePath, \"r\");\n const buf = Buffer.alloc(4);\n await fh.read(buf, 0, 4, 0);\n\n if (!buf.equals(ZIP_MAGIC)) {\n errors.push(\n \"File does not have valid ZIP magic bytes (PK\\\\x03\\\\x04). \" +\n \"Both AAB and APK files must be valid ZIP archives.\",\n );\n }\n } catch {\n errors.push(\"Unable to read file header for validation\");\n } finally {\n await fh?.close();\n }\n }\n\n return {\n valid: errors.length === 0,\n fileType,\n sizeBytes,\n errors,\n warnings,\n };\n}\n\nfunction formatSize(bytes: number): string {\n if (bytes >= 1024 * 1024 * 1024) {\n return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;\n }\n if (bytes >= 1024 * 1024) {\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n }\n if (bytes >= 1024) {\n return `${(bytes / 1024).toFixed(1)} KB`;\n }\n return `${bytes} B`;\n}\n","export const GOOGLE_PLAY_LANGUAGES: string[] = [\n \"af\",\n \"am\",\n \"ar\",\n \"hy-AM\",\n \"az-AZ\",\n \"eu-ES\",\n \"be\",\n \"bn-BD\",\n \"bg\",\n \"my-MM\",\n \"ca\",\n \"zh-HK\",\n \"zh-CN\",\n \"zh-TW\",\n \"hr\",\n \"cs-CZ\",\n \"da-DK\",\n \"nl-NL\",\n \"en-AU\",\n \"en-CA\",\n \"en-IN\",\n \"en-SG\",\n \"en-GB\",\n \"en-US\",\n \"et\",\n \"fil\",\n \"fi-FI\",\n \"fr-FR\",\n \"fr-CA\",\n \"gl-ES\",\n \"ka-GE\",\n \"de-DE\",\n \"el-GR\",\n \"gu\",\n \"iw-IL\",\n \"hi-IN\",\n \"hu-HU\",\n \"is-IS\",\n \"id\",\n \"it-IT\",\n \"ja-JP\",\n \"kn-IN\",\n \"kk\",\n \"km-KH\",\n \"ko-KR\",\n \"ky-KG\",\n \"lo-LA\",\n \"lv\",\n \"lt\",\n \"mk-MK\",\n \"ms\",\n \"ms-MY\",\n \"ml-IN\",\n \"mr-IN\",\n \"mn-MN\",\n \"ne-NP\",\n \"no-NO\",\n \"fa\",\n \"pl-PL\",\n \"pt-BR\",\n \"pt-PT\",\n \"pa\",\n \"ro\",\n \"rm\",\n \"ru-RU\",\n \"sr\",\n \"si-LK\",\n \"sk\",\n \"sl\",\n \"es-419\",\n \"es-ES\",\n \"es-US\",\n \"sw\",\n \"sv-SE\",\n \"ta-IN\",\n \"te-IN\",\n \"th\",\n \"tr-TR\",\n \"uk\",\n \"ur\",\n \"vi\",\n \"zu\",\n];\n\nexport function isValidBcp47(tag: string): boolean {\n return GOOGLE_PLAY_LANGUAGES.includes(tag);\n}\n","import { stat } from \"node:fs/promises\";\nimport { extname } from \"node:path\";\n\nexport interface ImageValidationResult {\n valid: boolean;\n warnings: string[];\n errors: string[];\n}\n\n// Google Play image size limits\nconst IMAGE_SIZE_LIMITS: Record<string, { maxBytes: number; label: string }> = {\n icon: { maxBytes: 1024 * 1024, label: \"1 MB\" },\n featureGraphic: { maxBytes: 1024 * 1024, label: \"1 MB\" },\n tvBanner: { maxBytes: 1024 * 1024, label: \"1 MB\" },\n phoneScreenshots: { maxBytes: 8 * 1024 * 1024, label: \"8 MB\" },\n sevenInchScreenshots: { maxBytes: 8 * 1024 * 1024, label: \"8 MB\" },\n tenInchScreenshots: { maxBytes: 8 * 1024 * 1024, label: \"8 MB\" },\n tvScreenshots: { maxBytes: 8 * 1024 * 1024, label: \"8 MB\" },\n wearScreenshots: { maxBytes: 8 * 1024 * 1024, label: \"8 MB\" },\n};\n\nconst VALID_EXTENSIONS = new Set([\".png\", \".jpg\", \".jpeg\"]);\nconst LARGE_IMAGE_THRESHOLD = 2 * 1024 * 1024; // 2 MB\n\nexport async function validateImage(\n filePath: string,\n imageType?: string,\n): Promise<ImageValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n // Check extension\n const ext = extname(filePath).toLowerCase();\n if (!VALID_EXTENSIONS.has(ext)) {\n errors.push(`Unsupported image format \"${ext}\". Use PNG or JPEG.`);\n }\n\n // Check file exists and size\n let sizeBytes: number;\n try {\n const stats = await stat(filePath);\n sizeBytes = stats.size;\n\n if (sizeBytes === 0) {\n errors.push(\"Image file is empty (0 bytes)\");\n }\n } catch {\n errors.push(`Image file not found: ${filePath}`);\n return { valid: false, errors, warnings };\n }\n\n // Check size limits per image type\n if (imageType && sizeBytes > 0) {\n const limit = IMAGE_SIZE_LIMITS[imageType];\n if (limit && sizeBytes > limit.maxBytes) {\n errors.push(`Image exceeds ${limit.label} limit for ${imageType} (${formatSize(sizeBytes)})`);\n }\n }\n\n // Warn about large images\n if (sizeBytes > LARGE_IMAGE_THRESHOLD && errors.length === 0) {\n warnings.push(\n `Large image (${formatSize(sizeBytes)}). Consider optimizing for faster upload and better store performance.`,\n );\n }\n\n // PNG optimization warning\n if (ext === \".png\" && sizeBytes > 512 * 1024) {\n warnings.push(\n \"PNG file is over 512 KB. Consider compressing with tools like pngquant or optipng.\",\n );\n }\n\n return { valid: errors.length === 0, errors, warnings };\n}\n\nfunction formatSize(bytes: number): string {\n if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n if (bytes >= 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${bytes} B`;\n}\n","import { readFile, writeFile, mkdir, readdir, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { Listing } from \"@gpc-cli/api\";\n\nconst FILE_MAP: Record<string, keyof Omit<Listing, \"language\">> = {\n \"title.txt\": \"title\",\n \"short_description.txt\": \"shortDescription\",\n \"full_description.txt\": \"fullDescription\",\n \"video.txt\": \"video\",\n};\n\nconst FIELD_TO_FILE: Record<string, string> = Object.fromEntries(\n Object.entries(FILE_MAP).map(([file, field]) => [field, file]),\n);\n\nexport interface ListingDiff {\n language: string;\n field: string;\n local: string;\n remote: string;\n}\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function readListingsFromDir(dir: string): Promise<Listing[]> {\n const listings: Listing[] = [];\n\n if (!(await exists(dir))) return listings;\n\n const entries = await readdir(dir);\n // Validate directory names to prevent path traversal\n const SAFE_LANG = /^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8})*$/;\n for (const lang of entries) {\n if (!SAFE_LANG.test(lang)) continue;\n const langDir = join(dir, lang);\n const langStat = await stat(langDir);\n if (!langStat.isDirectory()) continue;\n\n const listing: Listing = {\n language: lang,\n title: \"\",\n shortDescription: \"\",\n fullDescription: \"\",\n };\n\n for (const [fileName, field] of Object.entries(FILE_MAP)) {\n const filePath = join(langDir, fileName);\n if (await exists(filePath)) {\n const content = await readFile(filePath, \"utf-8\");\n (listing as unknown as Record<string, string>)[field] = content.trimEnd();\n }\n }\n\n listings.push(listing);\n }\n\n return listings;\n}\n\nexport async function writeListingsToDir(dir: string, listings: Listing[]): Promise<void> {\n for (const listing of listings) {\n const langDir = join(dir, listing.language);\n await mkdir(langDir, { recursive: true });\n\n for (const [field, fileName] of Object.entries(FIELD_TO_FILE)) {\n const value = (listing as unknown as Record<string, string>)[field];\n if (value !== undefined && value !== \"\") {\n await writeFile(join(langDir, fileName), value + \"\\n\", \"utf-8\");\n }\n }\n }\n}\n\nexport function diffListings(local: Listing[], remote: Listing[]): ListingDiff[] {\n const diffs: ListingDiff[] = [];\n const remoteMap = new Map(remote.map((l) => [l.language, l]));\n const localMap = new Map(local.map((l) => [l.language, l]));\n\n // Check all local listings against remote\n for (const localListing of local) {\n const remoteListing = remoteMap.get(localListing.language);\n for (const [field] of Object.entries(FIELD_TO_FILE)) {\n const localVal = (\n (localListing as unknown as Record<string, string>)[field] ?? \"\"\n ).toString();\n const remoteVal = remoteListing\n ? ((remoteListing as unknown as Record<string, string>)[field] ?? \"\").toString()\n : \"\";\n if (localVal !== remoteVal) {\n diffs.push({\n language: localListing.language,\n field,\n local: localVal,\n remote: remoteVal,\n });\n }\n }\n }\n\n // Check for remote-only languages\n for (const remoteListing of remote) {\n if (!localMap.has(remoteListing.language)) {\n for (const [field] of Object.entries(FIELD_TO_FILE)) {\n const remoteVal = (\n (remoteListing as unknown as Record<string, string>)[field] ?? \"\"\n ).toString();\n if (remoteVal) {\n diffs.push({\n language: remoteListing.language,\n field,\n local: \"\",\n remote: remoteVal,\n });\n }\n }\n }\n }\n\n return diffs;\n}\n","/** Listing text lint and diff utilities. No external deps — pure functions. */\n\nexport interface ListingFieldLimits {\n title: number;\n shortDescription: number;\n fullDescription: number;\n video: number;\n}\n\nexport const DEFAULT_LIMITS: ListingFieldLimits = {\n title: 30,\n shortDescription: 80,\n fullDescription: 4000,\n video: 256,\n};\n\nexport interface FieldLintResult {\n field: string;\n chars: number;\n limit: number;\n pct: number;\n status: \"ok\" | \"warn\" | \"over\";\n}\n\nexport interface ListingLintResult {\n language: string;\n fields: FieldLintResult[];\n valid: boolean;\n}\n\nexport interface LintableFields {\n title?: string;\n shortDescription?: string;\n fullDescription?: string;\n video?: string;\n [key: string]: string | undefined;\n}\n\n/** Lint a single listing's fields against character limits. */\nexport function lintListing(\n language: string,\n fields: LintableFields,\n limits: ListingFieldLimits = DEFAULT_LIMITS,\n): ListingLintResult {\n const fieldResults: FieldLintResult[] = [];\n\n for (const [field, limit] of Object.entries(limits) as [keyof ListingFieldLimits, number][]) {\n const value = fields[field] ?? \"\";\n const chars = [...value].length; // Unicode-aware char count\n const pct = Math.round((chars / limit) * 100);\n let status: FieldLintResult[\"status\"] = \"ok\";\n if (chars > limit) status = \"over\";\n else if (pct >= 80) status = \"warn\";\n fieldResults.push({ field, chars, limit, pct, status });\n }\n\n const valid = fieldResults.every((r) => r.status !== \"over\");\n return { language, fields: fieldResults, valid };\n}\n\n/** Lint multiple listings. */\nexport function lintListings(\n listings: { language: string; fields: LintableFields }[],\n limits?: ListingFieldLimits,\n): ListingLintResult[] {\n return listings.map((l) => lintListing(l.language, l.fields, limits));\n}\n\n// ---------------------------------------------------------------------------\n// Word-level diff (LCS-based)\n// ---------------------------------------------------------------------------\n\nexport interface DiffToken {\n text: string;\n type: \"equal\" | \"insert\" | \"delete\";\n}\n\nfunction tokenize(text: string): string[] {\n return text.split(/(\\s+)/);\n}\n\n/** Compute word-level LCS diff between two strings. */\nexport function wordDiff(before: string, after: string): DiffToken[] {\n const aTokens = tokenize(before);\n const bTokens = tokenize(after);\n const m = aTokens.length;\n const n = bTokens.length;\n\n // LCS DP\n const dp: number[][] = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0) as number[]);\n const cell = (r: number, c: number): number => dp[r]?.[c] ?? 0;\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n (dp[i] as number[])[j] =\n aTokens[i - 1] === bTokens[j - 1]\n ? cell(i - 1, j - 1) + 1\n : Math.max(cell(i - 1, j), cell(i, j - 1));\n }\n }\n\n // Backtrack\n const result: DiffToken[] = [];\n let i = m,\n j = n;\n while (i > 0 || j > 0) {\n if (i > 0 && j > 0 && aTokens[i - 1] === bTokens[j - 1]) {\n result.unshift({ text: aTokens[i - 1] ?? \"\", type: \"equal\" });\n i--;\n j--;\n } else if (j > 0 && (i === 0 || cell(i, j - 1) >= cell(i - 1, j))) {\n result.unshift({ text: bTokens[j - 1] ?? \"\", type: \"insert\" });\n j--;\n } else {\n result.unshift({ text: aTokens[i - 1] ?? \"\", type: \"delete\" });\n i--;\n }\n }\n return result;\n}\n\n/** Format a word diff as an inline string with +/- markers. */\nexport function formatWordDiff(diff: DiffToken[]): string {\n return diff\n .map((t) => {\n if (t.type === \"equal\") return t.text;\n if (t.type === \"insert\") return `[+${t.text}]`;\n return `[-${t.text}]`;\n })\n .join(\"\");\n}\n","import type {\n PlayApiClient,\n Listing,\n Image,\n ImageType,\n AppDetails,\n CountryAvailability,\n} from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\nimport { isValidBcp47 } from \"../utils/bcp47.js\";\nimport { validateImage } from \"../utils/image-validation.js\";\nimport { readListingsFromDir, writeListingsToDir, diffListings } from \"../utils/fastlane.js\";\nimport type { ListingDiff } from \"../utils/fastlane.js\";\nimport { lintListings, wordDiff, formatWordDiff } from \"../utils/listing-text.js\";\nimport type { ListingLintResult } from \"../utils/listing-text.js\";\n\nexport interface ListingsResult {\n listings: Listing[];\n}\n\nexport interface PushResult {\n updated: number;\n languages: string[];\n}\n\nexport interface DryRunResult {\n diffs: ListingDiff[];\n}\n\nfunction validateLanguage(lang: string): void {\n if (!isValidBcp47(lang)) {\n throw new GpcError(\n `Invalid language tag \"${lang}\". Must be a valid Google Play BCP 47 code.`,\n \"LISTING_INVALID_LANGUAGE\",\n 2,\n \"Use a valid BCP 47 language code such as en-US, de-DE, or ja-JP. See the Google Play Console for supported language codes.\",\n );\n }\n}\n\nexport async function getListings(\n client: PlayApiClient,\n packageName: string,\n language?: string,\n): Promise<Listing[]> {\n const edit = await client.edits.insert(packageName);\n try {\n let listings: Listing[];\n if (language) {\n validateLanguage(language);\n const listing = await client.listings.get(packageName, edit.id, language);\n listings = [listing];\n } else {\n listings = await client.listings.list(packageName, edit.id);\n }\n await client.edits.delete(packageName, edit.id);\n return listings;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function updateListing(\n client: PlayApiClient,\n packageName: string,\n language: string,\n data: Partial<Omit<Listing, \"language\">>,\n): Promise<Listing> {\n validateLanguage(language);\n const edit = await client.edits.insert(packageName);\n try {\n const listing = await client.listings.patch(packageName, edit.id, language, data);\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n return listing;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function deleteListing(\n client: PlayApiClient,\n packageName: string,\n language: string,\n): Promise<void> {\n validateLanguage(language);\n const edit = await client.edits.insert(packageName);\n try {\n await client.listings.delete(packageName, edit.id, language);\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function pullListings(\n client: PlayApiClient,\n packageName: string,\n dir: string,\n): Promise<ListingsResult> {\n const edit = await client.edits.insert(packageName);\n try {\n const listings = await client.listings.list(packageName, edit.id);\n await client.edits.delete(packageName, edit.id);\n await writeListingsToDir(dir, listings);\n return { listings };\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\n/** Lint local listing directory against Play Store character limits (no API call). */\nexport async function lintLocalListings(dir: string): Promise<ListingLintResult[]> {\n const localListings = await readListingsFromDir(dir);\n return lintListings(\n localListings.map((l) => ({\n language: l.language,\n fields: {\n title: l.title,\n shortDescription: l.shortDescription,\n fullDescription: l.fullDescription,\n video: l.video,\n },\n })),\n );\n}\n\n/** Analyze live Play Store listings for character limit compliance (requires API). */\nexport async function analyzeRemoteListings(\n client: PlayApiClient,\n packageName: string,\n options?: { expectedLocales?: string[] },\n): Promise<{ results: ListingLintResult[]; missingLocales?: string[] }> {\n const listings = await getListings(client, packageName);\n\n const results = lintListings(\n listings.map((l) => ({\n language: l.language,\n fields: {\n title: l.title,\n shortDescription: l.shortDescription,\n fullDescription: l.fullDescription,\n video: (l as unknown as Record<string, unknown>)[\"video\"] as string | undefined,\n },\n })),\n );\n\n let missingLocales: string[] | undefined;\n if (options?.expectedLocales) {\n const present = new Set(listings.map((l) => l.language));\n missingLocales = options.expectedLocales.filter((loc) => !present.has(loc));\n }\n\n return { results, missingLocales };\n}\n\n/** Enhanced diff: word-level inline diff for fullDescription, optional language filter. */\nexport async function diffListingsEnhanced(\n client: PlayApiClient,\n packageName: string,\n dir: string,\n options?: { lang?: string; wordLevel?: boolean },\n): Promise<ListingDiff[]> {\n const allDiffs = await diffListingsCommand(client, packageName, dir);\n let result = allDiffs;\n if (options?.lang) {\n result = allDiffs.filter((d) => d.language === options.lang);\n }\n if (options?.wordLevel) {\n return result.map((d) => {\n if (d.field === \"fullDescription\" && d.local && d.remote) {\n const diff = wordDiff(d.remote, d.local);\n return { ...d, diffSummary: formatWordDiff(diff) };\n }\n return d;\n });\n }\n return result;\n}\n\nexport async function pushListings(\n client: PlayApiClient,\n packageName: string,\n dir: string,\n options?: { dryRun?: boolean; force?: boolean },\n): Promise<PushResult | DryRunResult> {\n const localListings = await readListingsFromDir(dir);\n\n if (localListings.length === 0) {\n throw new GpcError(\n `No listings found in directory \"${dir}\"`,\n \"LISTING_DIR_EMPTY\",\n 1,\n `The directory must contain subdirectories named by language code (e.g., en-US/) with listing metadata files. Pull existing listings first with: gpc listings pull --dir \"${dir}\"`,\n );\n }\n\n // Validate all languages\n for (const listing of localListings) {\n validateLanguage(listing.language);\n }\n\n // Preflight lint: block push if any field exceeds limits (unless --force)\n if (!options?.force) {\n const lintResults = lintListings(\n localListings.map((l) => ({\n language: l.language,\n fields: {\n title: l.title,\n shortDescription: l.shortDescription,\n fullDescription: l.fullDescription,\n video: (l as unknown as Record<string, unknown>)[\"video\"] as string | undefined,\n },\n })),\n );\n const overLimit = lintResults.filter((r) => !r.valid);\n if (overLimit.length > 0) {\n const details = overLimit\n .map((r) => {\n const over = r.fields.filter((f) => f.status === \"over\");\n return `${r.language}: ${over.map((f) => `${f.field} (${f.chars}/${f.limit})`).join(\", \")}`;\n })\n .join(\"\\n\");\n throw new GpcError(\n `Listing push blocked: field(s) exceed character limits:\\n${details}`,\n \"LISTING_CHAR_LIMIT_EXCEEDED\",\n 1,\n \"Fix the character limit violations listed above, or use --force to push anyway.\",\n );\n }\n }\n\n const edit = await client.edits.insert(packageName);\n try {\n if (options?.dryRun) {\n const remoteListings = await client.listings.list(packageName, edit.id);\n await client.edits.delete(packageName, edit.id);\n const diffs = diffListings(localListings, remoteListings);\n return { diffs };\n }\n\n for (const listing of localListings) {\n const { language, ...data } = listing;\n await client.listings.update(packageName, edit.id, language, data);\n }\n\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n\n return {\n updated: localListings.length,\n languages: localListings.map((l) => l.language),\n };\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function listImages(\n client: PlayApiClient,\n packageName: string,\n language: string,\n imageType: ImageType,\n): Promise<Image[]> {\n validateLanguage(language);\n const edit = await client.edits.insert(packageName);\n try {\n const images = await client.images.list(packageName, edit.id, language, imageType);\n await client.edits.delete(packageName, edit.id);\n return images;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function uploadImage(\n client: PlayApiClient,\n packageName: string,\n language: string,\n imageType: ImageType,\n filePath: string,\n): Promise<Image> {\n validateLanguage(language);\n\n // Validate image before upload\n const imageCheck = await validateImage(filePath, imageType);\n if (!imageCheck.valid) {\n throw new GpcError(\n `Image validation failed: ${imageCheck.errors.join(\"; \")}`,\n \"IMAGE_INVALID\",\n 2,\n \"Check image dimensions, file size, and format. Google Play requires PNG or JPEG images within specific size limits per image type.\",\n );\n }\n for (const w of imageCheck.warnings) {\n process.emitWarning?.(w, \"ImageUploadWarning\");\n }\n\n const edit = await client.edits.insert(packageName);\n try {\n const image = await client.images.upload(packageName, edit.id, language, imageType, filePath);\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n return image;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function deleteImage(\n client: PlayApiClient,\n packageName: string,\n language: string,\n imageType: ImageType,\n imageId: string,\n): Promise<void> {\n validateLanguage(language);\n const edit = await client.edits.insert(packageName);\n try {\n await client.images.delete(packageName, edit.id, language, imageType, imageId);\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function diffListingsCommand(\n client: PlayApiClient,\n packageName: string,\n dir: string,\n): Promise<ListingDiff[]> {\n const localListings = await readListingsFromDir(dir);\n\n const edit = await client.edits.insert(packageName);\n try {\n const remoteListings = await client.listings.list(packageName, edit.id);\n await client.edits.delete(packageName, edit.id);\n return diffListings(localListings, remoteListings);\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function getCountryAvailability(\n client: PlayApiClient,\n packageName: string,\n track: string,\n): Promise<CountryAvailability> {\n const edit = await client.edits.insert(packageName);\n try {\n const availability = await client.countryAvailability.get(packageName, edit.id, track);\n await client.edits.delete(packageName, edit.id);\n return availability;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport interface ExportImagesOptions {\n lang?: string;\n type?: ImageType;\n}\n\nexport interface ExportImagesSummary {\n languages: number;\n images: number;\n totalSize: number;\n}\n\nconst ALL_IMAGE_TYPES: ImageType[] = [\n \"phoneScreenshots\",\n \"sevenInchScreenshots\",\n \"tenInchScreenshots\",\n \"tvScreenshots\",\n \"wearScreenshots\",\n \"icon\",\n \"featureGraphic\",\n \"tvBanner\",\n];\n\nexport async function exportImages(\n client: PlayApiClient,\n packageName: string,\n dir: string,\n options?: ExportImagesOptions,\n): Promise<ExportImagesSummary> {\n const { mkdir, writeFile } = await import(\"node:fs/promises\");\n const { join } = await import(\"node:path\");\n\n const edit = await client.edits.insert(packageName);\n try {\n // Determine languages\n let languages: string[];\n if (options?.lang) {\n validateLanguage(options.lang);\n languages = [options.lang];\n } else {\n const listings = await client.listings.list(packageName, edit.id);\n languages = listings.map((l) => l.language);\n }\n\n const imageTypes: ImageType[] = options?.type ? [options.type] : ALL_IMAGE_TYPES;\n\n let totalImages = 0;\n let totalSize = 0;\n\n // Collect all download tasks\n const tasks: Array<{ language: string; imageType: ImageType; url: string; index: number }> = [];\n\n for (const language of languages) {\n for (const imageType of imageTypes) {\n const images = await client.images.list(packageName, edit.id, language, imageType);\n for (let i = 0; i < images.length; i++) {\n const img = images[i];\n if (img && img.url) {\n tasks.push({ language, imageType, url: img.url, index: i + 1 });\n }\n }\n }\n }\n\n // Process downloads with concurrency limit of 5\n const concurrency = 5;\n for (let i = 0; i < tasks.length; i += concurrency) {\n const batch = tasks.slice(i, i + concurrency);\n const results = await Promise.all(\n batch.map(async (task) => {\n const dirPath = join(dir, task.language, task.imageType);\n await mkdir(dirPath, { recursive: true });\n\n const response = await fetch(task.url);\n if (!response.ok) {\n throw new GpcError(\n `Failed to download image: HTTP ${response.status} for ${task.imageType} (${task.language})`,\n \"LISTINGS_IMAGE_DOWNLOAD_FAILED\",\n 4,\n \"Check that the image URL is still valid. Re-run the export to retry.\",\n );\n }\n const buffer = Buffer.from(await response.arrayBuffer());\n const filePath = join(dirPath, `${task.index}.png`);\n await writeFile(filePath, buffer);\n\n return buffer.length;\n }),\n );\n\n for (const size of results) {\n totalImages++;\n totalSize += size;\n }\n }\n\n await client.edits.delete(packageName, edit.id);\n\n return {\n languages: languages.length,\n images: totalImages,\n totalSize,\n };\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function updateAppDetails(\n client: PlayApiClient,\n packageName: string,\n details: Partial<AppDetails>,\n): Promise<AppDetails> {\n const edit = await client.edits.insert(packageName);\n try {\n const result = await client.details.patch(packageName, edit.id, details);\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n return result;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n","import { readdir, readFile, writeFile, mkdir, access } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport interface FastlaneDetection {\n hasFastfile: boolean;\n hasAppfile: boolean;\n hasMetadata: boolean;\n hasGemfile: boolean;\n packageName?: string;\n jsonKeyPath?: string;\n lanes: FastlaneLane[];\n metadataLanguages: string[];\n parseWarnings: string[];\n}\n\nexport interface FastlaneLane {\n name: string;\n actions: string[];\n gpcEquivalent?: string;\n}\n\nexport interface MigrationResult {\n config: Record<string, unknown>;\n checklist: string[];\n warnings: string[];\n}\n\n// Ruby constructs that confuse the lane-end regex\nconst COMPLEX_RUBY_RE = /\\b(begin|rescue|ensure|if |unless |case |while |until |for )\\b/;\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function detectFastlane(cwd: string): Promise<FastlaneDetection> {\n const result: FastlaneDetection = {\n hasFastfile: false,\n hasAppfile: false,\n hasMetadata: false,\n hasGemfile: false,\n lanes: [],\n metadataLanguages: [],\n parseWarnings: [],\n };\n\n // Check for fastlane directory or root-level files\n const fastlaneDir = join(cwd, \"fastlane\");\n const hasFastlaneDir = await fileExists(fastlaneDir);\n\n const fastfilePath = hasFastlaneDir ? join(fastlaneDir, \"Fastfile\") : join(cwd, \"Fastfile\");\n const appfilePath = hasFastlaneDir ? join(fastlaneDir, \"Appfile\") : join(cwd, \"Appfile\");\n\n result.hasFastfile = await fileExists(fastfilePath);\n result.hasAppfile = await fileExists(appfilePath);\n result.hasGemfile = await fileExists(join(cwd, \"Gemfile\"));\n\n // Check for metadata directory\n const metadataDir = hasFastlaneDir\n ? join(fastlaneDir, \"metadata\", \"android\")\n : join(cwd, \"metadata\", \"android\");\n\n result.hasMetadata = await fileExists(metadataDir);\n\n if (result.hasMetadata) {\n try {\n const entries = await readdir(metadataDir, { withFileTypes: true });\n result.metadataLanguages = entries.filter((e) => e.isDirectory()).map((e) => e.name);\n } catch {\n result.parseWarnings.push(\"Could not read metadata directory — check permissions\");\n }\n }\n\n // Parse Fastfile if present\n if (result.hasFastfile) {\n try {\n const content = await readFile(fastfilePath, \"utf-8\");\n result.lanes = parseFastfile(content);\n\n // Warn if the Fastfile contains complex Ruby that may have been misread\n if (COMPLEX_RUBY_RE.test(content)) {\n result.parseWarnings.push(\n \"Fastfile contains complex Ruby constructs (begin/rescue/if/unless/case). \" +\n \"Lane detection may be incomplete — review MIGRATION.md and adjust manually.\",\n );\n }\n } catch {\n result.parseWarnings.push(\"Could not read Fastfile — check permissions\");\n }\n }\n\n // Parse Appfile if present\n if (result.hasAppfile) {\n try {\n const content = await readFile(appfilePath, \"utf-8\");\n const parsed = parseAppfile(content);\n result.packageName = parsed.packageName;\n result.jsonKeyPath = parsed.jsonKeyPath;\n } catch {\n result.parseWarnings.push(\"Could not read Appfile — check permissions\");\n }\n }\n\n return result;\n}\n\nexport function parseFastfile(content: string): FastlaneLane[] {\n const lanes: FastlaneLane[] = [];\n // Match lane blocks: lane :name do ... end\n const laneRegex = /lane\\s+:(\\w+)\\s+do([\\s\\S]*?)(?=\\bend\\b)/g;\n let match: RegExpExecArray | null;\n\n while ((match = laneRegex.exec(content)) !== null) {\n const name = match[1] ?? \"\";\n const body = match[2] ?? \"\";\n const actions: string[] = [];\n\n // Extract action calls\n const actionRegex =\n /\\b(supply|upload_to_play_store|capture_android_screenshots|deliver|gradle)\\b/g;\n let actionMatch: RegExpExecArray | null;\n while ((actionMatch = actionRegex.exec(body)) !== null) {\n const action = actionMatch[1] ?? \"\";\n if (!actions.includes(action)) {\n actions.push(action);\n }\n }\n\n // Determine GPC equivalent\n const gpcEquivalent = mapLaneToGpc(name, actions, body);\n\n lanes.push({ name, actions, gpcEquivalent });\n }\n\n return lanes;\n}\n\nfunction mapLaneToGpc(name: string, actions: string[], body: string): string | undefined {\n if (actions.includes(\"upload_to_play_store\") || actions.includes(\"supply\")) {\n const trackMatch = body.match(/track\\s*:\\s*[\"'](\\w+)[\"']/);\n const rolloutMatch = body.match(/rollout\\s*:\\s*[\"']?([\\d.]+)[\"']?/);\n\n if (rolloutMatch) {\n const raw = parseFloat(rolloutMatch[1] ?? \"0\");\n // Fastlane uses 0.0–1.0; convert to whole percentage for gpc\n const pct = raw > 1 ? Math.round(raw) : Math.round(raw * 100);\n return `gpc releases upload --rollout ${pct}${trackMatch ? ` --track ${trackMatch[1]}` : \"\"}`;\n }\n\n if (trackMatch) {\n return `gpc releases upload --track ${trackMatch[1]}`;\n }\n\n // Metadata-only supply\n if (body.match(/skip_upload_apk\\s*:\\s*true/) || body.match(/skip_upload_aab\\s*:\\s*true/)) {\n return \"gpc listings push\";\n }\n\n return \"gpc releases upload\";\n }\n\n if (actions.includes(\"capture_android_screenshots\")) {\n return undefined; // No equivalent\n }\n\n return undefined;\n}\n\nexport function parseAppfile(content: string): { packageName?: string; jsonKeyPath?: string } {\n const result: { packageName?: string; jsonKeyPath?: string } = {};\n\n // Match package_name(\"com.example.app\") or package_name \"com.example.app\"\n const pkgMatch = content.match(/package_name\\s*\\(?\\s*[\"']([^\"']+)[\"']\\s*\\)?/);\n if (pkgMatch) {\n result.packageName = pkgMatch[1];\n }\n\n // Match json_key_file(\"path/to/key.json\") or json_key_file \"path/to/key.json\"\n const keyMatch = content.match(/json_key_file\\s*\\(?\\s*[\"']([^\"']+)[\"']\\s*\\)?/);\n if (keyMatch) {\n result.jsonKeyPath = keyMatch[1];\n }\n\n return result;\n}\n\nexport function generateMigrationPlan(detection: FastlaneDetection): MigrationResult {\n const config: Record<string, unknown> = {};\n const checklist: string[] = [];\n const warnings: string[] = [...detection.parseWarnings];\n\n // Set package name if detected\n if (detection.packageName) {\n config[\"app\"] = detection.packageName;\n } else {\n checklist.push(\"Set your package name: gpc config set app <package-name>\");\n }\n\n // Set auth config if key path detected\n if (detection.jsonKeyPath) {\n config[\"auth\"] = { serviceAccount: detection.jsonKeyPath };\n } else {\n checklist.push(\"Configure authentication: gpc auth login\");\n }\n\n // Lane mappings\n for (const lane of detection.lanes) {\n if (lane.gpcEquivalent) {\n checklist.push(`Replace Fastlane lane \"${lane.name}\" with: ${lane.gpcEquivalent} <your.aab>`);\n }\n\n if (lane.actions.includes(\"capture_android_screenshots\")) {\n warnings.push(\n `Lane \"${lane.name}\" uses capture_android_screenshots which has no GPC equivalent. ` +\n \"Use a separate screenshot tool or check gpc plugins list for community plugins.\",\n );\n }\n\n // Lanes with no known action and no GPC equivalent\n if (\n lane.actions.length === 0 ||\n (lane.gpcEquivalent === undefined && !lane.actions.includes(\"capture_android_screenshots\"))\n ) {\n warnings.push(\n `Lane \"${lane.name}\" has no automatic GPC equivalent. ` +\n \"Check `gpc plugins list` or the plugin SDK docs to build a custom command.\",\n );\n }\n }\n\n // Metadata migration\n if (detection.hasMetadata && detection.metadataLanguages.length > 0) {\n const langs = detection.metadataLanguages.slice(0, 3).join(\", \");\n const more =\n detection.metadataLanguages.length > 3\n ? ` (+${detection.metadataLanguages.length - 3} more)`\n : \"\";\n checklist.push(\n `Pull current metadata for ${detection.metadataLanguages.length} language(s) (${langs}${more}): gpc listings pull --dir fastlane/metadata/android`,\n );\n checklist.push(\n \"Review pulled metadata, then push back: gpc listings push --dir fastlane/metadata/android\",\n );\n }\n\n // General checklist items\n checklist.push(\"Run gpc doctor to verify your setup\");\n checklist.push(\"Test each command with --dry-run before making real changes\");\n\n if (detection.hasGemfile) {\n checklist.push(\"Remove Fastlane from your Gemfile once migration is complete\");\n }\n\n // CI/CD reminder\n if (\n detection.lanes.some(\n (l) => l.actions.includes(\"supply\") || l.actions.includes(\"upload_to_play_store\"),\n )\n ) {\n checklist.push(\"Update CI/CD pipelines to call gpc commands instead of Fastlane lanes\");\n }\n\n return { config, checklist, warnings };\n}\n\nexport async function writeMigrationOutput(\n result: MigrationResult,\n dir: string,\n): Promise<string[]> {\n await mkdir(dir, { recursive: true });\n const files: string[] = [];\n\n // Write .gpcrc.json only if we have something meaningful to put in it\n if (Object.keys(result.config).length > 0) {\n const configPath = join(dir, \".gpcrc.json\");\n await writeFile(configPath, JSON.stringify(result.config, null, 2) + \"\\n\", \"utf-8\");\n files.push(configPath);\n }\n\n // Write MIGRATION.md\n const migrationPath = join(dir, \"MIGRATION.md\");\n const lines: string[] = [\n \"# Fastlane to GPC Migration\",\n \"\",\n \"Generated by `gpc migrate fastlane`. Review and adjust before applying.\",\n \"\",\n \"## Migration Checklist\",\n \"\",\n ];\n\n for (const item of result.checklist) {\n lines.push(`- [ ] ${item}`);\n }\n\n if (result.warnings.length > 0) {\n lines.push(\"\");\n lines.push(\"## Warnings\");\n lines.push(\"\");\n for (const warning of result.warnings) {\n lines.push(`> ⚠ ${warning}`);\n }\n }\n\n lines.push(\"\");\n lines.push(\"## Quick Reference\");\n lines.push(\"\");\n lines.push(\"| Fastlane | GPC |\");\n lines.push(\"|----------|-----|\");\n lines.push(\"| `fastlane supply` | `gpc releases upload` / `gpc listings push` |\");\n lines.push(\"| `upload_to_play_store` | `gpc releases upload` |\");\n lines.push('| `supply(track: \"internal\")` | `gpc releases upload --track internal` |');\n lines.push('| `supply(rollout: \"0.1\")` | `gpc releases upload --rollout 10` |');\n lines.push(\"| `supply(skip_upload_aab: true)` | `gpc listings push` |\");\n lines.push(\"| `capture_android_screenshots` | No equivalent — use separate tool |\");\n lines.push(\"\");\n lines.push(\n \"See the full migration guide: https://yasserstudio.github.io/gpc/migration/from-fastlane\",\n );\n lines.push(\"\");\n\n await writeFile(migrationPath, lines.join(\"\\n\"), \"utf-8\");\n files.push(migrationPath);\n\n return files;\n}\n","import { GpcError } from \"../errors.js\";\nimport { isValidBcp47 } from \"./bcp47.js\";\n\nconst PACKAGE_NAME_RE = /^[a-zA-Z][a-zA-Z0-9_]*(\\.[a-zA-Z][a-zA-Z0-9_]*){1,}$/;\nconst SKU_RE = /^[a-zA-Z0-9._]+$/;\nconst TRACK_NAMES = [\"internal\", \"alpha\", \"beta\", \"production\"];\nconst CUSTOM_TRACK_RE = /^[a-zA-Z0-9\\-_]+$/;\n\nexport function validatePackageName(name: string): void {\n if (!name || !PACKAGE_NAME_RE.test(name)) {\n throw new GpcError(\n `Invalid package name: \"${name}\"`,\n \"INVALID_PACKAGE_NAME\",\n 2,\n \"Package name must be a valid Android application ID (e.g., com.example.myapp)\",\n );\n }\n}\n\nexport function validateVersionCode(code: string | number): void {\n const num = typeof code === \"string\" ? parseInt(code, 10) : code;\n if (!Number.isInteger(num) || num < 1) {\n throw new GpcError(\n `Invalid version code: \"${code}\"`,\n \"INVALID_VERSION_CODE\",\n 2,\n \"Version code must be a positive integer (e.g., 142)\",\n );\n }\n}\n\nexport function validateLanguageCode(code: string): void {\n if (!code || !isValidBcp47(code)) {\n throw new GpcError(\n `Invalid language code: \"${code}\"`,\n \"INVALID_LANGUAGE_CODE\",\n 2,\n \"Language code must be a valid BCP-47 tag supported by Google Play (e.g., en-US, ja-JP, fr-FR)\",\n );\n }\n}\n\nexport function validateTrackName(name: string): void {\n if (!name) {\n throw new GpcError(\n \"Track name is required\",\n \"INVALID_TRACK_NAME\",\n 2,\n \"Specify a track: internal, alpha, beta, production, or a custom track name\",\n );\n }\n if (!TRACK_NAMES.includes(name) && !CUSTOM_TRACK_RE.test(name)) {\n throw new GpcError(\n `Invalid track name: \"${name}\"`,\n \"INVALID_TRACK_NAME\",\n 2,\n `Valid tracks: ${TRACK_NAMES.join(\", \")}, or a custom track matching [a-zA-Z0-9-_]+`,\n );\n }\n}\n\nexport function validateSku(sku: string): void {\n if (!sku || !SKU_RE.test(sku)) {\n throw new GpcError(\n `Invalid product ID (SKU): \"${sku}\"`,\n \"INVALID_SKU\",\n 2,\n \"Product ID must contain only letters, numbers, dots, and underscores (e.g., premium_upgrade)\",\n );\n }\n}\n","import { readdir, readFile, stat } from \"node:fs/promises\";\nimport { extname, basename, join } from \"node:path\";\nimport { GpcError } from \"../errors.js\";\n\nexport interface ReleaseNote {\n language: string;\n text: string;\n}\n\nexport interface ReleaseNotesValidation {\n valid: boolean;\n errors: string[];\n warnings: string[];\n}\n\nconst MAX_NOTES_LENGTH = 500;\n\nexport async function readReleaseNotesFromDir(dir: string): Promise<ReleaseNote[]> {\n let entries: string[];\n try {\n entries = await readdir(dir);\n } catch {\n throw new GpcError(\n `Release notes directory not found: ${dir}`,\n \"RELEASE_NOTES_DIR_NOT_FOUND\",\n 1,\n `Create the directory and add .txt files named by language code (e.g., en-US.txt). Path: ${dir}`,\n );\n }\n\n const notes: ReleaseNote[] = [];\n\n for (const entry of entries) {\n if (extname(entry) !== \".txt\") continue;\n\n const language = basename(entry, \".txt\");\n const filePath = join(dir, entry);\n\n const stats = await stat(filePath);\n if (!stats.isFile()) continue;\n\n const text = (await readFile(filePath, \"utf-8\")).trim();\n if (text.length === 0) continue;\n\n notes.push({ language, text });\n }\n\n return notes;\n}\n\nexport function validateReleaseNotes(notes: ReleaseNote[]): ReleaseNotesValidation {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n const seen = new Set<string>();\n for (const note of notes) {\n if (seen.has(note.language)) {\n errors.push(`Duplicate language code: ${note.language}`);\n }\n seen.add(note.language);\n\n if (note.text.length > MAX_NOTES_LENGTH) {\n warnings.push(\n `Release notes for \"${note.language}\" are ${note.text.length} chars (max ${MAX_NOTES_LENGTH}) — Google Play will reject notes exceeding this limit`,\n );\n }\n }\n\n return { valid: errors.length === 0, errors, warnings };\n}\n","import { stat } from \"node:fs/promises\";\nimport { validateUploadFile } from \"../utils/file-validation.js\";\nimport { readReleaseNotesFromDir, validateReleaseNotes } from \"../utils/release-notes.js\";\n\nexport interface ValidateOptions {\n filePath: string;\n mappingFile?: string;\n track?: string;\n notes?: { language: string; text: string }[];\n notesDir?: string;\n}\n\nexport interface ValidateCheck {\n name: string;\n passed: boolean;\n message: string;\n}\n\nexport interface ValidateResult {\n valid: boolean;\n checks: ValidateCheck[];\n warnings: string[];\n}\n\nconst STANDARD_TRACKS = new Set([\n \"internal\",\n \"qa\",\n \"alpha\",\n \"beta\",\n \"production\",\n // Form factor tracks\n \"wear:internal\",\n \"wear:alpha\",\n \"wear:beta\",\n \"wear:production\",\n \"automotive:internal\",\n \"automotive:alpha\",\n \"automotive:beta\",\n \"automotive:production\",\n \"tv:internal\",\n \"tv:alpha\",\n \"tv:beta\",\n \"tv:production\",\n \"android_xr:internal\",\n \"android_xr:alpha\",\n \"android_xr:beta\",\n \"android_xr:production\",\n \"google_play_games_pc:internal\",\n \"google_play_games_pc:alpha\",\n \"google_play_games_pc:beta\",\n \"google_play_games_pc:production\",\n]);\nconst TRACK_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_:-]*$/;\n\nexport async function validatePreSubmission(options: ValidateOptions): Promise<ValidateResult> {\n const checks: ValidateCheck[] = [];\n\n const resultWarnings: string[] = [];\n\n // 1. File validation\n const fileResult = await validateUploadFile(options.filePath);\n checks.push({\n name: \"file\",\n passed: fileResult.valid,\n message: fileResult.valid\n ? `Valid ${fileResult.fileType.toUpperCase()} (${formatSize(fileResult.sizeBytes)})`\n : fileResult.errors.join(\"; \"),\n });\n // Surface file validation warnings (e.g. large file upload time notice)\n for (const w of fileResult.warnings) {\n resultWarnings.push(w);\n }\n\n // 2. Mapping file\n if (options.mappingFile) {\n try {\n const stats = await stat(options.mappingFile);\n checks.push({\n name: \"mapping\",\n passed: stats.isFile(),\n message: stats.isFile()\n ? `Mapping file found (${formatSize(stats.size)})`\n : \"Mapping path is not a file\",\n });\n } catch {\n checks.push({\n name: \"mapping\",\n passed: false,\n message: `Mapping file not found: ${options.mappingFile}`,\n });\n }\n }\n\n // 3. Track validation\n if (options.track) {\n const isValid = STANDARD_TRACKS.has(options.track) || TRACK_PATTERN.test(options.track);\n checks.push({\n name: \"track\",\n passed: isValid,\n message: isValid\n ? `Track \"${options.track}\" is valid`\n : `Invalid track name \"${options.track}\". Use: internal, alpha, beta, production, or a custom track ID`,\n });\n }\n\n // 4. Release notes validation\n let resolvedNotes = options.notes;\n if (options.notesDir) {\n try {\n resolvedNotes = await readReleaseNotesFromDir(options.notesDir);\n checks.push({\n name: \"notes-dir\",\n passed: true,\n message: `Read release notes for ${resolvedNotes.length} language(s)`,\n });\n } catch (err) {\n checks.push({\n name: \"notes-dir\",\n passed: false,\n message: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n if (resolvedNotes && resolvedNotes.length > 0) {\n const notesResult = validateReleaseNotes(resolvedNotes);\n checks.push({\n name: \"notes\",\n passed: notesResult.valid,\n message: notesResult.valid\n ? `Release notes valid (${resolvedNotes.length} language(s))`\n : notesResult.errors.join(\"; \"),\n });\n for (const w of notesResult.warnings) resultWarnings.push(w);\n }\n\n return {\n valid: checks.every((c) => c.passed),\n checks,\n warnings: resultWarnings,\n };\n}\n\nfunction formatSize(bytes: number): string {\n if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n if (bytes >= 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${bytes} B`;\n}\n","import type { PlayApiClient } from \"@gpc-cli/api\";\nimport { uploadRelease } from \"./releases.js\";\nimport type { UploadResult, DryRunUploadResult } from \"./releases.js\";\nimport { validatePreSubmission } from \"./validate.js\";\nimport type { ValidateResult } from \"./validate.js\";\nimport { readReleaseNotesFromDir } from \"../utils/release-notes.js\";\n\nexport interface PublishOptions {\n track?: string;\n rolloutPercent?: number;\n notes?: string;\n notesDir?: string;\n releaseName?: string;\n mappingFile?: string;\n dryRun?: boolean;\n}\n\nexport interface PublishResult {\n validation: ValidateResult;\n upload?: UploadResult;\n}\n\nexport interface DryRunPublishResult {\n dryRun: true;\n validation: ValidateResult;\n upload: DryRunUploadResult;\n}\n\nexport async function publish(\n client: PlayApiClient,\n packageName: string,\n filePath: string,\n options: PublishOptions,\n): Promise<PublishResult | DryRunPublishResult> {\n // Resolve release notes\n let releaseNotes: { language: string; text: string }[] | undefined;\n if (options.notesDir) {\n releaseNotes = await readReleaseNotesFromDir(options.notesDir);\n } else if (options.notes) {\n releaseNotes = [{ language: \"en-US\", text: options.notes }];\n }\n\n // Validate\n const validation = await validatePreSubmission({\n filePath,\n mappingFile: options.mappingFile,\n track: options.track || \"internal\",\n notes: releaseNotes,\n });\n\n if (options.dryRun) {\n const upload = (await uploadRelease(client, packageName, filePath, {\n track: options.track || \"internal\",\n userFraction: options.rolloutPercent ? options.rolloutPercent / 100 : undefined,\n dryRun: true,\n })) as DryRunUploadResult;\n\n return { dryRun: true, validation, upload };\n }\n\n if (!validation.valid) {\n return { validation };\n }\n\n // Upload\n const upload = await uploadRelease(client, packageName, filePath, {\n track: options.track || \"internal\",\n userFraction: options.rolloutPercent ? options.rolloutPercent / 100 : undefined,\n releaseNotes,\n releaseName: options.releaseName,\n mappingFile: options.mappingFile,\n });\n\n return { validation, upload } as PublishResult;\n}\n","import type { PlayApiClient, Review, ReviewsListOptions, ReviewReplyResponse } from \"@gpc-cli/api\";\nimport { paginateAll } from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\nimport { analyzeReviews as analyzeReviewsSentiment } from \"../utils/sentiment.js\";\nimport type { ReviewAnalysis } from \"../utils/sentiment.js\";\n\nexport interface ReviewsFilterOptions {\n stars?: number;\n language?: string;\n since?: string;\n translationLanguage?: string;\n maxResults?: number;\n limit?: number;\n nextPage?: string;\n all?: boolean;\n}\n\nexport interface ReviewExportOptions extends ReviewsFilterOptions {\n format?: \"json\" | \"csv\";\n}\n\nexport async function listReviews(\n client: PlayApiClient,\n packageName: string,\n options?: ReviewsFilterOptions,\n): Promise<Review[]> {\n let reviews: Review[];\n\n if (options?.all) {\n // Auto-paginate all pages\n const { items } = await paginateAll<Review>(async (pageToken) => {\n const apiOptions: ReviewsListOptions = { token: pageToken };\n if (options?.translationLanguage) apiOptions.translationLanguage = options.translationLanguage;\n if (options?.maxResults) apiOptions.maxResults = options.maxResults;\n const response = await client.reviews.list(packageName, apiOptions);\n return {\n items: response.reviews || [],\n nextPageToken: response.tokenPagination?.nextPageToken,\n };\n }, { limit: options?.limit });\n reviews = items;\n } else {\n // Single page (default)\n const apiOptions: ReviewsListOptions = {};\n if (options?.translationLanguage) apiOptions.translationLanguage = options.translationLanguage;\n if (options?.maxResults) apiOptions.maxResults = options.maxResults;\n if (options?.nextPage) apiOptions.token = options.nextPage;\n\n const response = await client.reviews.list(packageName, apiOptions);\n reviews = response.reviews || [];\n }\n\n // Client-side filters\n if (options?.stars !== undefined) {\n reviews = reviews.filter((r) => {\n const userComment = r.comments?.[0]?.userComment;\n return userComment && userComment.starRating === options.stars;\n });\n }\n\n if (options?.language) {\n reviews = reviews.filter((r) => {\n const userComment = r.comments?.[0]?.userComment;\n return userComment?.reviewerLanguage === options.language;\n });\n }\n\n if (options?.since) {\n const sinceTime = new Date(options.since).getTime() / 1000;\n reviews = reviews.filter((r) => {\n const userComment = r.comments?.[0]?.userComment;\n return userComment && Number(userComment.lastModified.seconds) >= sinceTime;\n });\n }\n\n return reviews;\n}\n\nexport async function getReview(\n client: PlayApiClient,\n packageName: string,\n reviewId: string,\n translationLanguage?: string,\n): Promise<Review> {\n return client.reviews.get(packageName, reviewId, translationLanguage);\n}\n\nconst MAX_REPLY_LENGTH = 350;\n\nexport async function replyToReview(\n client: PlayApiClient,\n packageName: string,\n reviewId: string,\n replyText: string,\n): Promise<ReviewReplyResponse> {\n if (replyText.length > MAX_REPLY_LENGTH) {\n throw new GpcError(\n `Reply text exceeds ${MAX_REPLY_LENGTH} characters (${replyText.length}). Google Play limits replies to ${MAX_REPLY_LENGTH} characters.`,\n \"REVIEW_REPLY_TOO_LONG\",\n 2,\n `Shorten your reply to ${MAX_REPLY_LENGTH} characters or fewer. Current length: ${replyText.length}.`,\n );\n }\n if (replyText.length === 0) {\n throw new GpcError(\n \"Reply text cannot be empty.\",\n \"REVIEW_REPLY_EMPTY\",\n 2,\n \"Provide a non-empty reply text with --text or -t.\",\n );\n }\n return client.reviews.reply(packageName, reviewId, replyText);\n}\n\nexport async function exportReviews(\n client: PlayApiClient,\n packageName: string,\n options?: ReviewExportOptions,\n): Promise<string> {\n const { items: allReviews } = await paginateAll<Review>(async (pageToken) => {\n const apiOptions: ReviewsListOptions = { token: pageToken };\n if (options?.translationLanguage) apiOptions.translationLanguage = options.translationLanguage;\n const response = await client.reviews.list(packageName, apiOptions);\n return {\n items: response.reviews || [],\n nextPageToken: response.tokenPagination?.nextPageToken,\n };\n });\n\n let filtered = allReviews;\n\n if (options?.stars !== undefined) {\n filtered = filtered.filter((r) => {\n const uc = r.comments?.[0]?.userComment;\n return uc && uc.starRating === options.stars;\n });\n }\n\n if (options?.language) {\n filtered = filtered.filter((r) => {\n const uc = r.comments?.[0]?.userComment;\n return uc?.reviewerLanguage === options.language;\n });\n }\n\n if (options?.since) {\n const sinceTime = new Date(options.since).getTime() / 1000;\n filtered = filtered.filter((r) => {\n const uc = r.comments?.[0]?.userComment;\n return uc && Number(uc.lastModified.seconds) >= sinceTime;\n });\n }\n\n if (options?.format === \"csv\") {\n return reviewsToCsv(filtered);\n }\n\n return JSON.stringify(filtered, null, 2);\n}\n\nfunction reviewsToCsv(reviews: Review[]): string {\n const header = \"reviewId,authorName,starRating,text,language,date,device,appVersionName\";\n const rows = reviews.map((r) => {\n const uc = r.comments?.[0]?.userComment;\n const fields = [\n r.reviewId,\n csvEscape(r.authorName),\n uc?.starRating ?? \"\",\n csvEscape(uc?.text ?? \"\"),\n uc?.reviewerLanguage ?? \"\",\n uc ? new Date(Number(uc.lastModified.seconds) * 1000).toISOString() : \"\",\n csvEscape(uc?.device ?? \"\"),\n csvEscape(uc?.appVersionName ?? \"\"),\n ];\n return fields.join(\",\");\n });\n return [header, ...rows].join(\"\\n\");\n}\n\nfunction csvEscape(value: string): string {\n if (value.includes(\",\") || value.includes('\"') || value.includes(\"\\n\")) {\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\n }\n return value;\n}\n\nexport { ReviewAnalysis };\n\n/** Fetch reviews and run local sentiment/topic/keyword analysis. */\nexport async function analyzeReviews(\n client: PlayApiClient,\n packageName: string,\n options?: ReviewsFilterOptions,\n): Promise<ReviewAnalysis> {\n const reviews = await listReviews(client, packageName, options);\n\n const items = reviews.map((r) => {\n const uc = r.comments?.[0]?.userComment;\n return {\n text: uc?.text ?? \"\",\n rating: uc?.starRating,\n };\n });\n\n return analyzeReviewsSentiment(items);\n}\n","/**\n * Local NLP sentiment analysis for reviews. No external API required.\n * Pure functions — no mocks needed in tests.\n */\n\nexport interface SentimentResult {\n score: number; // -1 to +1\n label: \"positive\" | \"negative\" | \"neutral\";\n magnitude: number; // 0 to 1 (confidence)\n}\n\nexport interface TopicCluster {\n topic: string;\n count: number;\n avgScore: number;\n}\n\nexport interface KeywordFrequency {\n word: string;\n count: number;\n}\n\nexport interface ReviewAnalysis {\n totalReviews: number;\n avgRating: number;\n sentiment: {\n positive: number;\n negative: number;\n neutral: number;\n avgScore: number;\n };\n topics: TopicCluster[];\n keywords: KeywordFrequency[];\n ratingDistribution: Record<number, number>;\n}\n\n// Simple lexicon-based sentiment analysis\nconst POSITIVE_WORDS = new Set([\n \"great\",\n \"excellent\",\n \"amazing\",\n \"awesome\",\n \"fantastic\",\n \"love\",\n \"good\",\n \"best\",\n \"perfect\",\n \"wonderful\",\n \"helpful\",\n \"easy\",\n \"fast\",\n \"smooth\",\n \"reliable\",\n \"clean\",\n \"beautiful\",\n \"intuitive\",\n \"works\",\n \"recommend\",\n \"useful\",\n \"thank\",\n \"thanks\",\n \"brilliant\",\n \"superb\",\n \"flawless\",\n \"outstanding\",\n \"delightful\",\n \"nice\",\n]);\n\nconst NEGATIVE_WORDS = new Set([\n \"bad\",\n \"terrible\",\n \"awful\",\n \"horrible\",\n \"worst\",\n \"hate\",\n \"broken\",\n \"crash\",\n \"crashes\",\n \"bug\",\n \"bugs\",\n \"slow\",\n \"laggy\",\n \"freeze\",\n \"freezes\",\n \"error\",\n \"errors\",\n \"fail\",\n \"fails\",\n \"useless\",\n \"disappointing\",\n \"disappointed\",\n \"frustrating\",\n \"frustration\",\n \"annoying\",\n \"problem\",\n \"problems\",\n \"issue\",\n \"issues\",\n \"fix\",\n \"please\",\n \"not working\",\n \"doesn't work\",\n \"stopped\",\n \"uninstall\",\n \"deleted\",\n \"waste\",\n \"rubbish\",\n \"garbage\",\n \"terrible\",\n]);\n\nconst STOP_WORDS = new Set([\n \"the\",\n \"a\",\n \"an\",\n \"and\",\n \"or\",\n \"but\",\n \"in\",\n \"on\",\n \"at\",\n \"to\",\n \"for\",\n \"of\",\n \"with\",\n \"is\",\n \"it\",\n \"this\",\n \"that\",\n \"was\",\n \"are\",\n \"be\",\n \"been\",\n \"have\",\n \"has\",\n \"had\",\n \"do\",\n \"does\",\n \"did\",\n \"will\",\n \"would\",\n \"could\",\n \"should\",\n \"may\",\n \"might\",\n \"i\",\n \"me\",\n \"my\",\n \"we\",\n \"you\",\n \"he\",\n \"she\",\n \"they\",\n \"them\",\n \"their\",\n \"its\",\n \"not\",\n \"no\",\n \"very\",\n \"so\",\n \"just\",\n \"really\",\n \"app\",\n \"application\",\n \"update\",\n]);\n\n/** Analyze sentiment of a single text. */\nexport function analyzeSentiment(text: string): SentimentResult {\n const lower = text.toLowerCase();\n const words = lower.split(/\\W+/).filter(Boolean);\n\n let posScore = 0;\n let negScore = 0;\n\n for (const word of words) {\n if (POSITIVE_WORDS.has(word)) posScore++;\n if (NEGATIVE_WORDS.has(word)) negScore++;\n }\n\n const total = posScore + negScore;\n if (total === 0) return { score: 0, label: \"neutral\", magnitude: 0 };\n\n const score = (posScore - negScore) / total;\n const magnitude = Math.min(1, total / 10);\n const label = score > 0.1 ? \"positive\" : score < -0.1 ? \"negative\" : \"neutral\";\n\n return { score, label, magnitude };\n}\n\n/** Cluster reviews into topics based on keyword co-occurrence. */\nexport function clusterTopics(texts: string[]): TopicCluster[] {\n const TOPIC_KEYWORDS: Record<string, string[]> = {\n performance: [\"slow\", \"lag\", \"laggy\", \"freeze\", \"fast\", \"speed\", \"quick\", \"smooth\"],\n crashes: [\"crash\", \"crashes\", \"crash\", \"crashing\", \"force close\", \"stops\", \"stopped\"],\n \"ui/ux\": [\"ui\", \"design\", \"interface\", \"layout\", \"button\", \"screen\", \"menu\", \"navigation\"],\n battery: [\"battery\", \"drain\", \"power\", \"charging\", \"drain\"],\n updates: [\"update\", \"updated\", \"version\", \"new version\", \"after update\"],\n notifications: [\"notification\", \"notifications\", \"alert\", \"alerts\", \"push\"],\n \"login/auth\": [\"login\", \"sign in\", \"logout\", \"password\", \"account\", \"auth\"],\n \"feature requests\": [\"please add\", \"would be nice\", \"missing\", \"need\", \"wish\", \"want\"],\n bugs: [\"bug\", \"bugs\", \"issue\", \"error\", \"problem\", \"glitch\", \"broken\"],\n pricing: [\"price\", \"pricing\", \"expensive\", \"cheap\", \"subscription\", \"pay\", \"cost\", \"free\"],\n };\n\n const clusterMap = new Map<string, { count: number; totalScore: number }>();\n\n for (const text of texts) {\n const lower = text.toLowerCase();\n const sentiment = analyzeSentiment(text);\n\n for (const [topic, keywords] of Object.entries(TOPIC_KEYWORDS)) {\n if (keywords.some((kw) => lower.includes(kw))) {\n const existing = clusterMap.get(topic) ?? { count: 0, totalScore: 0 };\n clusterMap.set(topic, {\n count: existing.count + 1,\n totalScore: existing.totalScore + sentiment.score,\n });\n }\n }\n }\n\n return Array.from(clusterMap.entries())\n .map(([topic, { count, totalScore }]) => ({\n topic,\n count,\n avgScore: count > 0 ? Math.round((totalScore / count) * 100) / 100 : 0,\n }))\n .filter((c) => c.count > 0)\n .sort((a, b) => b.count - a.count);\n}\n\n/** Count word frequency (excluding stop words). */\nexport function keywordFrequency(texts: string[], topN = 20): KeywordFrequency[] {\n const freq = new Map<string, number>();\n\n for (const text of texts) {\n const words = text\n .toLowerCase()\n .split(/\\W+/)\n .filter((w) => w.length > 3 && !STOP_WORDS.has(w));\n for (const word of words) {\n freq.set(word, (freq.get(word) ?? 0) + 1);\n }\n }\n\n return Array.from(freq.entries())\n .map(([word, count]) => ({ word, count }))\n .sort((a, b) => b.count - a.count)\n .slice(0, topN);\n}\n\n/** Full review analysis: sentiment, topics, keywords, rating distribution. */\nexport function analyzeReviews(reviews: { text: string; rating?: number }[]): ReviewAnalysis {\n if (reviews.length === 0) {\n return {\n totalReviews: 0,\n avgRating: 0,\n sentiment: { positive: 0, negative: 0, neutral: 0, avgScore: 0 },\n topics: [],\n keywords: [],\n ratingDistribution: {},\n };\n }\n\n const texts = reviews.map((r) => r.text);\n const sentiments = texts.map((t) => analyzeSentiment(t));\n\n const positive = sentiments.filter((s) => s.label === \"positive\").length;\n const negative = sentiments.filter((s) => s.label === \"negative\").length;\n const neutral = sentiments.filter((s) => s.label === \"neutral\").length;\n const avgScore = sentiments.reduce((sum, s) => sum + s.score, 0) / sentiments.length;\n\n const ratings = reviews.map((r) => r.rating).filter((r): r is number => r !== undefined);\n const avgRating = ratings.length > 0 ? ratings.reduce((a, b) => a + b, 0) / ratings.length : 0;\n\n const ratingDistribution: Record<number, number> = {};\n for (const r of ratings) {\n ratingDistribution[r] = (ratingDistribution[r] ?? 0) + 1;\n }\n\n return {\n totalReviews: reviews.length,\n avgRating: Math.round(avgRating * 100) / 100,\n sentiment: {\n positive,\n negative,\n neutral,\n avgScore: Math.round(avgScore * 100) / 100,\n },\n topics: clusterTopics(texts),\n keywords: keywordFrequency(texts),\n ratingDistribution,\n };\n}\n","import type {\n PlayApiClient,\n Subscription,\n BasePlanMigratePricesRequest,\n SubscriptionOffer,\n OffersListResponse,\n Money,\n} from \"@gpc-cli/api\";\nimport { paginateAll } from \"@gpc-cli/api\";\nimport { validatePackageName, validateSku } from \"../utils/validation.js\";\nimport { GpcError } from \"../errors.js\";\n\nexport interface ListSubscriptionsOptions {\n pageToken?: string;\n pageSize?: number;\n limit?: number;\n nextPage?: string;\n}\n\n// --- Sanitization: strip output-only fields, coerce types ---\n\nfunction coerceMoneyUnits(money: Money): Money {\n if (money.units !== undefined && typeof money.units !== \"string\") {\n return { ...money, units: String(money.units) };\n }\n return money;\n}\n\nfunction sanitizeSubscription(data: Subscription): Subscription {\n const { ...cleaned } = data;\n // Strip output-only fields from top level\n delete (cleaned as Record<string, unknown>)[\"state\"];\n delete (cleaned as Record<string, unknown>)[\"archived\"];\n\n if (cleaned.basePlans) {\n cleaned.basePlans = cleaned.basePlans.map((bp) => {\n const { state: _state, archived: _archived, ...cleanBp } = bp;\n void _state;\n void _archived;\n // Coerce Money.units to string in regional configs\n if (cleanBp.regionalConfigs) {\n cleanBp.regionalConfigs = cleanBp.regionalConfigs.map((rc) => ({\n ...rc,\n price: coerceMoneyUnits(rc.price),\n }));\n }\n return cleanBp;\n });\n }\n return cleaned;\n}\n\nfunction sanitizeOffer(data: SubscriptionOffer): SubscriptionOffer {\n const { state: _state2, ...cleaned } = data;\n void _state2;\n delete (cleaned as Record<string, unknown>)[\"archived\"];\n return cleaned as SubscriptionOffer;\n}\n\n// --- Client-side validation ---\n\nfunction parseDuration(iso: string): number {\n const match = iso.match(/^P(\\d+)D$/);\n return match?.[1] ? parseInt(match[1], 10) : 0;\n}\n\nconst PRORATION_MODE_PREFIX = \"SUBSCRIPTION_PRORATION_MODE_\";\nconst VALID_PRORATION_MODES = [\n \"SUBSCRIPTION_PRORATION_MODE_CHARGE_ON_NEXT_BILLING_DATE\",\n \"SUBSCRIPTION_PRORATION_MODE_CHARGE_FULL_PRICE_IMMEDIATELY\",\n];\n\nfunction autoFixProrationMode(data: Subscription): void {\n if (!data.basePlans) return;\n for (const bp of data.basePlans) {\n const mode = bp.autoRenewingBasePlanType?.prorationMode;\n if (mode && !mode.startsWith(PRORATION_MODE_PREFIX)) {\n if (bp.autoRenewingBasePlanType)\n bp.autoRenewingBasePlanType.prorationMode = `${PRORATION_MODE_PREFIX}${mode}`;\n }\n if (bp.autoRenewingBasePlanType?.prorationMode) {\n const fullMode = bp.autoRenewingBasePlanType.prorationMode;\n if (!VALID_PRORATION_MODES.includes(fullMode)) {\n throw new GpcError(\n `Invalid prorationMode: \"${fullMode}\"`,\n \"INVALID_SUBSCRIPTION_DATA\",\n 2,\n `Valid values: ${VALID_PRORATION_MODES.join(\", \")}`,\n );\n }\n }\n }\n}\n\nfunction validateSubscriptionData(data: Subscription): void {\n // Auto-fix prorationMode prefix\n autoFixProrationMode(data);\n\n // Validate listings\n if (data.listings) {\n for (const [lang, listing] of Object.entries(data.listings)) {\n if (listing.benefits && listing.benefits.length > 4) {\n throw new GpcError(\n `Listing \"${lang}\" has ${listing.benefits.length} benefits (max 4)`,\n \"INVALID_SUBSCRIPTION_DATA\",\n 2,\n \"Google Play allows a maximum of 4 benefits per subscription listing\",\n );\n }\n if (listing.description && listing.description.length > 80) {\n throw new GpcError(\n `Listing \"${lang}\" description is ${listing.description.length} chars (max 80)`,\n \"INVALID_SUBSCRIPTION_DATA\",\n 2,\n \"Google Play limits subscription descriptions to 80 characters\",\n );\n }\n }\n }\n\n // Validate base plan durations\n if (data.basePlans) {\n for (const bp of data.basePlans) {\n const autoType = bp.autoRenewingBasePlanType;\n if (autoType?.gracePeriodDuration && autoType?.accountHoldDuration) {\n const grace = parseDuration(autoType.gracePeriodDuration);\n const hold = parseDuration(autoType.accountHoldDuration);\n const sum = grace + hold;\n if (sum < 30 || sum > 60) {\n throw new GpcError(\n `Base plan \"${bp.basePlanId}\": gracePeriodDuration (${grace}d) + accountHoldDuration (${hold}d) = ${sum}d (must be 30-60)`,\n \"INVALID_SUBSCRIPTION_DATA\",\n 2,\n \"gracePeriodDuration + accountHoldDuration must sum to between P30D and P60D\",\n );\n }\n }\n }\n }\n}\n\nexport async function listSubscriptions(\n client: PlayApiClient,\n packageName: string,\n options?: ListSubscriptionsOptions,\n): Promise<{ subscriptions: Subscription[]; nextPageToken?: string }> {\n validatePackageName(packageName);\n if (options?.limit || options?.nextPage) {\n const result = await paginateAll<Subscription>(\n async (pageToken) => {\n const resp = await client.subscriptions.list(packageName, {\n pageToken,\n pageSize: options?.pageSize,\n });\n return { items: resp.subscriptions || [], nextPageToken: resp.nextPageToken };\n },\n { limit: options.limit, startPageToken: options.nextPage },\n );\n return { subscriptions: result.items, nextPageToken: result.nextPageToken };\n }\n return client.subscriptions.list(packageName, {\n pageToken: options?.pageToken,\n pageSize: options?.pageSize,\n });\n}\n\nexport async function getSubscription(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n): Promise<Subscription> {\n validatePackageName(packageName);\n validateSku(productId);\n return client.subscriptions.get(packageName, productId);\n}\n\nexport async function createSubscription(\n client: PlayApiClient,\n packageName: string,\n data: Subscription,\n): Promise<Subscription> {\n validatePackageName(packageName);\n validateSubscriptionData(data);\n const sanitized = sanitizeSubscription(data);\n return client.subscriptions.create(packageName, sanitized, data.productId);\n}\n\nconst SUBSCRIPTION_ID_FIELDS = new Set([\"productId\", \"packageName\"]);\n\nfunction deriveSubscriptionUpdateMask(data: Subscription): string {\n return Object.keys(data)\n .filter((k) => !SUBSCRIPTION_ID_FIELDS.has(k))\n .join(\",\");\n}\n\nexport async function updateSubscription(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n data: Subscription,\n updateMask?: string,\n): Promise<Subscription> {\n validatePackageName(packageName);\n validateSku(productId);\n validateSubscriptionData(data);\n const sanitized = sanitizeSubscription(data);\n const mask = updateMask || deriveSubscriptionUpdateMask(data);\n return client.subscriptions.update(packageName, productId, sanitized, mask);\n}\n\nexport async function deleteSubscription(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n): Promise<void> {\n validatePackageName(packageName);\n validateSku(productId);\n return client.subscriptions.delete(packageName, productId);\n}\n\nexport async function activateBasePlan(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n basePlanId: string,\n): Promise<Subscription> {\n validatePackageName(packageName);\n validateSku(productId);\n return client.subscriptions.activateBasePlan(packageName, productId, basePlanId);\n}\n\nexport async function deactivateBasePlan(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n basePlanId: string,\n): Promise<Subscription> {\n validatePackageName(packageName);\n validateSku(productId);\n return client.subscriptions.deactivateBasePlan(packageName, productId, basePlanId);\n}\n\nexport async function deleteBasePlan(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n basePlanId: string,\n): Promise<void> {\n validatePackageName(packageName);\n validateSku(productId);\n return client.subscriptions.deleteBasePlan(packageName, productId, basePlanId);\n}\n\nexport async function migratePrices(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n basePlanId: string,\n data: BasePlanMigratePricesRequest,\n): Promise<Subscription> {\n validatePackageName(packageName);\n validateSku(productId);\n return client.subscriptions.migratePrices(packageName, productId, basePlanId, data);\n}\n\nexport async function listOffers(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n basePlanId: string,\n): Promise<OffersListResponse> {\n validatePackageName(packageName);\n validateSku(productId);\n return client.subscriptions.listOffers(packageName, productId, basePlanId);\n}\n\nexport async function getOffer(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n): Promise<SubscriptionOffer> {\n validatePackageName(packageName);\n validateSku(productId);\n return client.subscriptions.getOffer(packageName, productId, basePlanId, offerId);\n}\n\nexport async function createOffer(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n basePlanId: string,\n data: SubscriptionOffer,\n): Promise<SubscriptionOffer> {\n validatePackageName(packageName);\n validateSku(productId);\n const sanitized = sanitizeOffer(data);\n return client.subscriptions.createOffer(\n packageName,\n productId,\n basePlanId,\n sanitized,\n data.offerId,\n );\n}\n\nconst OFFER_ID_FIELDS = new Set([\"productId\", \"basePlanId\", \"offerId\"]);\n\nfunction deriveOfferUpdateMask(data: SubscriptionOffer): string {\n return Object.keys(data)\n .filter((k) => !OFFER_ID_FIELDS.has(k))\n .join(\",\");\n}\n\nexport async function updateOffer(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n data: SubscriptionOffer,\n updateMask?: string,\n): Promise<SubscriptionOffer> {\n validatePackageName(packageName);\n validateSku(productId);\n const sanitized = sanitizeOffer(data);\n const mask = updateMask || deriveOfferUpdateMask(data);\n return client.subscriptions.updateOffer(\n packageName,\n productId,\n basePlanId,\n offerId,\n sanitized,\n mask,\n );\n}\n\nexport async function deleteOffer(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n): Promise<void> {\n validatePackageName(packageName);\n validateSku(productId);\n return client.subscriptions.deleteOffer(packageName, productId, basePlanId, offerId);\n}\n\nexport async function activateOffer(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n): Promise<SubscriptionOffer> {\n validatePackageName(packageName);\n validateSku(productId);\n return client.subscriptions.activateOffer(packageName, productId, basePlanId, offerId);\n}\n\nexport interface SubscriptionDiff {\n field: string;\n local: string;\n remote: string;\n}\n\nexport async function diffSubscription(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n localData: Subscription,\n): Promise<SubscriptionDiff[]> {\n validatePackageName(packageName);\n validateSku(productId);\n const remote = await client.subscriptions.get(packageName, productId);\n const diffs: SubscriptionDiff[] = [];\n const fieldsToCompare = [\"listings\", \"basePlans\", \"taxAndComplianceSettings\"];\n\n for (const field of fieldsToCompare) {\n const localVal = JSON.stringify(\n (localData as unknown as Record<string, unknown>)[field] ?? null,\n );\n const remoteVal = JSON.stringify((remote as unknown as Record<string, unknown>)[field] ?? null);\n if (localVal !== remoteVal) {\n diffs.push({ field, local: localVal, remote: remoteVal });\n }\n }\n return diffs;\n}\n\nexport async function deactivateOffer(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n basePlanId: string,\n offerId: string,\n): Promise<SubscriptionOffer> {\n validatePackageName(packageName);\n validateSku(productId);\n return client.subscriptions.deactivateOffer(packageName, productId, basePlanId, offerId);\n}\n\nexport interface SubscriptionAnalytics {\n totalSubscriptions: number;\n activeCount: number;\n activeBasePlans: number;\n trialBasePlans: number;\n pausedBasePlans: number;\n canceledBasePlans: number;\n offerCount: number;\n byProductId: Array<{\n productId: string;\n state: string;\n basePlanCount: number;\n offerCount: number;\n }>;\n}\n\n/** Aggregate subscription catalog analytics from the Play API. */\nexport async function getSubscriptionAnalytics(\n client: PlayApiClient,\n packageName: string,\n): Promise<SubscriptionAnalytics> {\n validatePackageName(packageName);\n\n const { items: subs } = await paginateAll<Subscription>(async (pageToken) => {\n const response = await client.subscriptions.list(packageName, {\n pageToken,\n pageSize: 100,\n });\n return {\n items: response.subscriptions || [],\n nextPageToken: response.nextPageToken,\n };\n });\n\n let activeCount = 0;\n let activeBasePlans = 0;\n let trialBasePlans = 0;\n let pausedBasePlans = 0;\n let canceledBasePlans = 0;\n let totalOffers = 0;\n\n const byProductId: SubscriptionAnalytics[\"byProductId\"] = [];\n\n for (const sub of subs) {\n const state = (sub as unknown as Record<string, unknown>)[\"state\"] as string | undefined;\n if (state === \"ACTIVE\") activeCount++;\n\n const basePlans = sub.basePlans ?? [];\n let subOfferCount = 0;\n\n for (const bp of basePlans) {\n const bpState = (bp as unknown as Record<string, unknown>)[\"state\"] as string | undefined;\n if (bpState === \"ACTIVE\") activeBasePlans++;\n else if (bpState === \"DRAFT\") trialBasePlans++;\n else if (bpState === \"INACTIVE\") pausedBasePlans++;\n else if (bpState === \"PREPUBLISHED\") canceledBasePlans++;\n }\n\n // Count offers across all base plans\n for (const bp of basePlans) {\n try {\n const offersResp = await client.subscriptions.listOffers(\n packageName,\n sub.productId,\n bp.basePlanId,\n );\n const offers = offersResp.subscriptionOffers ?? [];\n subOfferCount += offers.length;\n totalOffers += offers.length;\n } catch {\n // offers may not be accessible for all base plans\n }\n }\n\n byProductId.push({\n productId: sub.productId,\n state: ((sub as unknown as Record<string, unknown>)[\"state\"] as string) ?? \"UNKNOWN\",\n basePlanCount: basePlans.length,\n offerCount: subOfferCount,\n });\n }\n\n return {\n totalSubscriptions: subs.length,\n activeCount,\n activeBasePlans,\n trialBasePlans,\n pausedBasePlans,\n canceledBasePlans,\n offerCount: totalOffers,\n byProductId,\n };\n}\n","import type {\n ReportingApiClient,\n VitalsMetricSet,\n MetricSetQuery,\n MetricSetResponse,\n MetricRow,\n AnomalyDetectionResponse,\n ErrorIssuesResponse,\n ReportingDimension,\n ReportingAggregation,\n} from \"@gpc-cli/api\";\n\nexport interface VitalsQueryOptions {\n dimension?: ReportingDimension;\n days?: number;\n aggregation?: ReportingAggregation;\n}\n\nexport interface VitalsOverview {\n crashRate?: MetricRow[];\n anrRate?: MetricRow[];\n slowStartRate?: MetricRow[];\n slowRenderingRate?: MetricRow[];\n excessiveWakeupRate?: MetricRow[];\n stuckWakelockRate?: MetricRow[];\n}\n\nexport interface ThresholdResult {\n breached: boolean;\n value: number | undefined;\n threshold: number;\n}\n\nconst METRIC_SET_METRICS: Record<VitalsMetricSet, string[]> = {\n crashRateMetricSet: [\"crashRate\", \"userPerceivedCrashRate\", \"distinctUsers\"],\n anrRateMetricSet: [\"anrRate\", \"userPerceivedAnrRate\", \"distinctUsers\"],\n slowStartRateMetricSet: [\"slowStartRate\", \"distinctUsers\"],\n slowRenderingRateMetricSet: [\"slowRenderingRate\", \"distinctUsers\"],\n excessiveWakeupRateMetricSet: [\"excessiveWakeupRate\", \"distinctUsers\"],\n stuckBackgroundWakelockRateMetricSet: [\n \"stuckBgWakelockRate\",\n \"stuckBgWakelockRate7dUserWeighted\",\n \"stuckBgWakelockRate28dUserWeighted\",\n \"distinctUsers\",\n ],\n errorCountMetricSet: [\"errorReportCount\", \"distinctUsers\"],\n};\n\nfunction buildQuery(metricSet: VitalsMetricSet, options?: VitalsQueryOptions): MetricSetQuery {\n const metrics = METRIC_SET_METRICS[metricSet] ?? [\"errorReportCount\", \"distinctUsers\"];\n\n const days = options?.days ?? 30;\n const DAY_MS = 24 * 60 * 60 * 1000;\n const end = new Date(Date.now() - DAY_MS); // API data lags ~1 day; cap to yesterday\n const start = new Date(Date.now() - DAY_MS - days * DAY_MS);\n\n const query: MetricSetQuery = {\n metrics,\n timelineSpec: {\n aggregationPeriod: options?.aggregation ?? \"DAILY\",\n startTime: {\n year: start.getUTCFullYear(),\n month: start.getUTCMonth() + 1,\n day: start.getUTCDate(),\n },\n endTime: {\n year: end.getUTCFullYear(),\n month: end.getUTCMonth() + 1,\n day: end.getUTCDate(),\n },\n },\n };\n\n if (options?.dimension) {\n query.dimensions = [options.dimension];\n }\n\n return query;\n}\n\nasync function queryMetric(\n reporting: ReportingApiClient,\n packageName: string,\n metricSet: VitalsMetricSet,\n options?: VitalsQueryOptions,\n): Promise<MetricSetResponse> {\n const query = buildQuery(metricSet, options);\n return reporting.queryMetricSet(packageName, metricSet, query);\n}\n\nexport async function getVitalsOverview(\n reporting: ReportingApiClient,\n packageName: string,\n): Promise<VitalsOverview> {\n const metricSets: [VitalsMetricSet, keyof VitalsOverview][] = [\n [\"crashRateMetricSet\", \"crashRate\"],\n [\"anrRateMetricSet\", \"anrRate\"],\n [\"slowStartRateMetricSet\", \"slowStartRate\"],\n [\"slowRenderingRateMetricSet\", \"slowRenderingRate\"],\n [\"excessiveWakeupRateMetricSet\", \"excessiveWakeupRate\"],\n [\"stuckBackgroundWakelockRateMetricSet\", \"stuckWakelockRate\"],\n ];\n\n const results = await Promise.allSettled(\n metricSets.map(([metric]) => reporting.queryMetricSet(packageName, metric, buildQuery(metric))),\n );\n\n const overview: VitalsOverview = {};\n for (let i = 0; i < metricSets.length; i++) {\n const entry = metricSets[i];\n if (!entry) continue;\n const key = entry[1];\n const result = results[i];\n if (!result) continue;\n if (result.status === \"fulfilled\") {\n overview[key] = result.value.rows || [];\n }\n }\n\n return overview;\n}\n\nexport async function getVitalsCrashes(\n reporting: ReportingApiClient,\n packageName: string,\n options?: VitalsQueryOptions,\n): Promise<MetricSetResponse> {\n return queryMetric(reporting, packageName, \"crashRateMetricSet\", options);\n}\n\nexport async function getVitalsAnr(\n reporting: ReportingApiClient,\n packageName: string,\n options?: VitalsQueryOptions,\n): Promise<MetricSetResponse> {\n return queryMetric(reporting, packageName, \"anrRateMetricSet\", options);\n}\n\nexport async function getVitalsStartup(\n reporting: ReportingApiClient,\n packageName: string,\n options?: VitalsQueryOptions,\n): Promise<MetricSetResponse> {\n // API requires startType as a dimension for slowStartRateMetricSet;\n // auto-include it if no dimension is explicitly specified\n const opts = options?.dimension\n ? options\n : { ...options, dimension: \"startType\" as ReportingDimension };\n return queryMetric(reporting, packageName, \"slowStartRateMetricSet\", opts);\n}\n\nexport async function getVitalsRendering(\n reporting: ReportingApiClient,\n packageName: string,\n options?: VitalsQueryOptions,\n): Promise<MetricSetResponse> {\n return queryMetric(reporting, packageName, \"slowRenderingRateMetricSet\", options);\n}\n\nexport async function getVitalsBattery(\n reporting: ReportingApiClient,\n packageName: string,\n options?: VitalsQueryOptions,\n): Promise<MetricSetResponse> {\n return queryMetric(reporting, packageName, \"excessiveWakeupRateMetricSet\", options);\n}\n\nexport async function getVitalsMemory(\n reporting: ReportingApiClient,\n packageName: string,\n options?: VitalsQueryOptions,\n): Promise<MetricSetResponse> {\n return queryMetric(reporting, packageName, \"stuckBackgroundWakelockRateMetricSet\", options);\n}\n\n/** LMK-specific query: enforces DAILY aggregation as required by the API. */\nexport async function getVitalsLmk(\n reporting: ReportingApiClient,\n packageName: string,\n options?: VitalsQueryOptions,\n): Promise<MetricSetResponse> {\n return queryMetric(reporting, packageName, \"stuckBackgroundWakelockRateMetricSet\", {\n ...options,\n aggregation: \"DAILY\",\n });\n}\n\nexport async function getVitalsAnomalies(\n reporting: ReportingApiClient,\n packageName: string,\n): Promise<AnomalyDetectionResponse> {\n return reporting.getAnomalies(packageName);\n}\n\nexport async function searchVitalsErrors(\n reporting: ReportingApiClient,\n packageName: string,\n options?: { filter?: string; maxResults?: number },\n): Promise<ErrorIssuesResponse> {\n return reporting.searchErrorIssues(packageName, options?.filter, options?.maxResults);\n}\n\nexport interface VitalsTrendComparison {\n metric: string;\n current: number | undefined;\n previous: number | undefined;\n changePercent: number | undefined;\n direction: \"improved\" | \"degraded\" | \"unchanged\" | \"unknown\";\n}\n\nexport async function compareVitalsTrend(\n reporting: ReportingApiClient,\n packageName: string,\n metricSet: VitalsMetricSet,\n days: number = 7,\n): Promise<VitalsTrendComparison> {\n const DAY_MS = 24 * 60 * 60 * 1000;\n const nowMs = Date.now();\n\n // Cap to 2 days ago — API data typically lags 1-2 days; using 2 ensures\n // the endTime is always within the available data window.\n const baseMs = nowMs - 2 * DAY_MS;\n\n // Current period: [base - days, base]\n const currentEnd = new Date(baseMs);\n const currentStart = new Date(baseMs - days * DAY_MS);\n\n // Previous period: [base - 2*days - 1, base - days - 1] (1-day gap)\n const previousEnd = new Date(baseMs - days * DAY_MS - DAY_MS);\n const previousStart = new Date(baseMs - days * DAY_MS - DAY_MS - days * DAY_MS);\n\n const metrics = METRIC_SET_METRICS[metricSet] ?? [\"errorReportCount\", \"distinctUsers\"];\n\n // Use UTC accessors to avoid timezone-dependent off-by-one on date boundaries\n const toApiDate = (d: Date) => ({\n year: d.getUTCFullYear(),\n month: d.getUTCMonth() + 1,\n day: d.getUTCDate(),\n });\n\n const makeQuery = (start: Date, end: Date): MetricSetQuery => ({\n metrics,\n timelineSpec: {\n aggregationPeriod: \"DAILY\",\n startTime: toApiDate(start),\n endTime: toApiDate(end),\n },\n });\n\n const [currentResult, previousResult] = await Promise.all([\n reporting.queryMetricSet(packageName, metricSet, makeQuery(currentStart, currentEnd)),\n reporting.queryMetricSet(packageName, metricSet, makeQuery(previousStart, previousEnd)),\n ]);\n\n const extractAvg = (rows: MetricRow[] | undefined): number | undefined => {\n if (!rows || rows.length === 0) return undefined;\n const values = rows\n .map((r) => {\n const keys = Object.keys(r.metrics);\n const first = keys[0];\n return first ? Number(r.metrics[first]?.decimalValue?.value) : NaN;\n })\n .filter((v) => !isNaN(v));\n if (values.length === 0) return undefined;\n return values.reduce((a, b) => a + b, 0) / values.length;\n };\n\n const current = extractAvg(currentResult.rows);\n const previous = extractAvg(previousResult.rows);\n\n let changePercent: number | undefined;\n let direction: VitalsTrendComparison[\"direction\"] = \"unknown\";\n\n if (current !== undefined && previous !== undefined && previous !== 0) {\n changePercent = ((current - previous) / previous) * 100;\n if (Math.abs(changePercent) < 1) {\n direction = \"unchanged\";\n } else if (changePercent < 0) {\n direction = \"improved\"; // lower error rate = better\n } else {\n direction = \"degraded\";\n }\n }\n\n return {\n metric: metricSet,\n current,\n previous,\n changePercent: changePercent !== undefined ? Math.round(changePercent * 10) / 10 : undefined,\n direction,\n };\n}\n\nexport function checkThreshold(value: number | undefined, threshold: number): ThresholdResult {\n return {\n breached: value !== undefined && value > threshold,\n value,\n threshold,\n };\n}\n\nexport interface VersionVitalsRow {\n versionCode: string;\n crashRate?: number;\n anrRate?: number;\n slowStartRate?: number;\n slowRenderingRate?: number;\n}\n\nexport interface VersionVitalsComparison {\n v1: VersionVitalsRow;\n v2: VersionVitalsRow;\n regressions: string[];\n}\n\n/** Compare vitals side-by-side for two version codes. */\nexport async function compareVersionVitals(\n reporting: ReportingApiClient,\n packageName: string,\n v1: string,\n v2: string,\n options?: { days?: number },\n): Promise<VersionVitalsComparison> {\n const days = options?.days ?? 30;\n const metricSets: [VitalsMetricSet, keyof Omit<VersionVitalsRow, \"versionCode\">][] = [\n [\"crashRateMetricSet\", \"crashRate\"],\n [\"anrRateMetricSet\", \"anrRate\"],\n [\"slowStartRateMetricSet\", \"slowStartRate\"],\n [\"slowRenderingRateMetricSet\", \"slowRenderingRate\"],\n ];\n\n const results = await Promise.allSettled(\n metricSets.map(([ms]) =>\n queryMetric(reporting, packageName, ms, { dimension: \"versionCode\", days }),\n ),\n );\n\n const row1: VersionVitalsRow = { versionCode: v1 };\n const row2: VersionVitalsRow = { versionCode: v2 };\n\n for (let i = 0; i < metricSets.length; i++) {\n const entry = metricSets[i];\n const result = results[i];\n if (!entry || !result || result.status !== \"fulfilled\") continue;\n const key = entry[1];\n const rows = result.value.rows ?? [];\n\n const extractAvgForVersion = (vc: string): number | undefined => {\n const matching = rows.filter((r) => {\n const dims = r.dimensions as Record<string, unknown>[] | undefined;\n return dims?.some((d) => (d as Record<string, unknown>)[\"stringValue\"] === vc) ?? false;\n });\n if (matching.length === 0) return undefined;\n const values = matching\n .map((r) => {\n const firstKey = Object.keys(r.metrics)[0];\n return firstKey ? Number(r.metrics[firstKey]?.decimalValue?.value) : NaN;\n })\n .filter((v) => !isNaN(v));\n if (values.length === 0) return undefined;\n return values.reduce((a, b) => a + b, 0) / values.length;\n };\n\n (row1 as unknown as Record<string, unknown>)[key] = extractAvgForVersion(v1);\n (row2 as unknown as Record<string, unknown>)[key] = extractAvgForVersion(v2);\n }\n\n const regressions: string[] = [];\n for (const [, key] of metricSets) {\n const val1 = (row1 as unknown as Record<string, unknown>)[key] as number | undefined;\n const val2 = (row2 as unknown as Record<string, unknown>)[key] as number | undefined;\n if (val1 !== undefined && val2 !== undefined && val2 > val1 * 1.05) {\n regressions.push(key as string);\n }\n }\n\n return { v1: row1, v2: row2, regressions };\n}\n\nexport interface WatchVitalsOptions {\n /** Polling interval in milliseconds. Defaults to 5 minutes. */\n intervalMs?: number;\n /** Threshold value; breach triggers halt. */\n threshold: number;\n /** Metric set to monitor. Defaults to crashRateMetricSet. */\n metricSet?: VitalsMetricSet;\n /** Called when threshold is breached. Implement halt logic here. */\n onHalt?: (value: number) => Promise<void>;\n /** Called on each poll result (value may be undefined if no data). */\n onPoll?: (value: number | undefined, breached: boolean) => void;\n}\n\n/**\n * Poll vitals on an interval; invoke onHalt if threshold is breached.\n * Returns a stop function — call it to cancel the watch loop.\n */\nexport function watchVitalsWithAutoHalt(\n reporting: ReportingApiClient,\n packageName: string,\n options: WatchVitalsOptions,\n): () => void {\n const {\n intervalMs = 5 * 60 * 1000,\n threshold,\n metricSet = \"crashRateMetricSet\",\n onHalt,\n onPoll,\n } = options;\n\n let stopped = false;\n let haltTriggered = false;\n\n const poll = async () => {\n if (stopped) return;\n try {\n const result = await queryMetric(reporting, packageName, metricSet, { days: 1 });\n const latestRow = result.rows?.[result.rows.length - 1];\n const firstMetric = latestRow?.metrics ? Object.keys(latestRow.metrics)[0] : undefined;\n const value = firstMetric\n ? Number(latestRow?.metrics[firstMetric]?.decimalValue?.value)\n : undefined;\n\n const breached = value !== undefined && value > threshold;\n onPoll?.(value, breached);\n\n if (breached && !haltTriggered && onHalt) {\n haltTriggered = true;\n await onHalt(value as number);\n }\n } catch {\n // swallow errors in background polling\n }\n\n if (!stopped) {\n timerId = setTimeout(poll, intervalMs);\n }\n };\n\n let timerId = setTimeout(poll, 0);\n\n return () => {\n stopped = true;\n clearTimeout(timerId);\n };\n}\n","import { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { PlayApiClient, InAppProduct, InAppProductsBatchUpdateRequest } from \"@gpc-cli/api\";\nimport { paginateAll } from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\n\nexport interface ListIapOptions {\n token?: string;\n maxResults?: number;\n limit?: number;\n nextPage?: string;\n}\n\nexport async function listInAppProducts(\n client: PlayApiClient,\n packageName: string,\n options?: ListIapOptions,\n): Promise<{ inappproduct: InAppProduct[]; nextPageToken?: string }> {\n if (options?.limit || options?.nextPage) {\n const result = await paginateAll<InAppProduct>(\n async (pageToken) => {\n const resp = await client.inappproducts.list(packageName, {\n token: pageToken,\n maxResults: options?.maxResults,\n });\n return {\n items: resp.inappproduct || [],\n nextPageToken: resp.tokenPagination?.nextPageToken,\n };\n },\n { limit: options.limit, startPageToken: options.nextPage },\n );\n return { inappproduct: result.items, nextPageToken: result.nextPageToken };\n }\n return client.inappproducts.list(packageName, {\n token: options?.token,\n maxResults: options?.maxResults,\n });\n}\n\nexport async function getInAppProduct(\n client: PlayApiClient,\n packageName: string,\n sku: string,\n): Promise<InAppProduct> {\n return client.inappproducts.get(packageName, sku);\n}\n\nexport async function createInAppProduct(\n client: PlayApiClient,\n packageName: string,\n data: InAppProduct,\n): Promise<InAppProduct> {\n return client.inappproducts.create(packageName, data);\n}\n\nexport async function updateInAppProduct(\n client: PlayApiClient,\n packageName: string,\n sku: string,\n data: InAppProduct,\n): Promise<InAppProduct> {\n return client.inappproducts.update(packageName, sku, data);\n}\n\nexport async function deleteInAppProduct(\n client: PlayApiClient,\n packageName: string,\n sku: string,\n): Promise<void> {\n return client.inappproducts.delete(packageName, sku);\n}\n\nexport interface SyncResult {\n created: number;\n updated: number;\n unchanged: number;\n skus: string[];\n}\n\nexport async function syncInAppProducts(\n client: PlayApiClient,\n packageName: string,\n dir: string,\n options?: { dryRun?: boolean },\n): Promise<SyncResult> {\n const localProducts = await readProductsFromDir(dir);\n\n if (localProducts.length === 0) {\n return { created: 0, updated: 0, unchanged: 0, skus: [] };\n }\n\n const response = await client.inappproducts.list(packageName);\n const remoteSkus = new Set((response.inappproduct || []).map((p) => p.sku));\n\n const toUpdate = localProducts.filter((p) => remoteSkus.has(p.sku));\n const toCreate = localProducts.filter((p) => !remoteSkus.has(p.sku));\n const skus = localProducts.map((p) => p.sku);\n\n if (options?.dryRun) {\n return { created: toCreate.length, updated: toUpdate.length, unchanged: 0, skus };\n }\n\n // Attempt batch update for products that need updating (multiple items)\n if (toUpdate.length > 1) {\n try {\n await batchUpdateProducts(client, packageName, toUpdate);\n } catch {\n // Fallback to serial updates\n for (const product of toUpdate) {\n await client.inappproducts.update(packageName, product.sku, product);\n }\n }\n } else {\n for (const product of toUpdate) {\n await client.inappproducts.update(packageName, product.sku, product);\n }\n }\n\n for (const product of toCreate) {\n await client.inappproducts.create(packageName, product);\n }\n\n return { created: toCreate.length, updated: toUpdate.length, unchanged: 0, skus };\n}\n\nconst BATCH_CHUNK_SIZE = 100;\n\nasync function batchUpdateProducts(\n client: PlayApiClient,\n packageName: string,\n products: InAppProduct[],\n): Promise<InAppProduct[]> {\n const results: InAppProduct[] = [];\n for (let i = 0; i < products.length; i += BATCH_CHUNK_SIZE) {\n const chunk = products.slice(i, i + BATCH_CHUNK_SIZE);\n const request: InAppProductsBatchUpdateRequest = {\n requests: chunk.map((p) => ({\n inappproduct: p,\n packageName,\n sku: p.sku,\n })),\n };\n const response = await client.inappproducts.batchUpdate(packageName, request);\n results.push(...(response.inappproducts || []));\n }\n return results;\n}\n\nasync function readProductsFromDir(dir: string): Promise<InAppProduct[]> {\n const files = await readdir(dir);\n const jsonFiles = files.filter((f) => f.endsWith(\".json\"));\n const localProducts: InAppProduct[] = [];\n for (const file of jsonFiles) {\n const content = await readFile(join(dir, file), \"utf-8\");\n try {\n localProducts.push(JSON.parse(content) as InAppProduct);\n } catch {\n throw new GpcError(\n `Failed to parse ${file}: invalid JSON`,\n \"IAP_INVALID_JSON\",\n 1,\n `Check that \"${file}\" contains valid JSON. You can validate it with: cat \"${file}\" | jq .`,\n );\n }\n }\n return localProducts;\n}\n\nexport interface BatchSyncResult extends SyncResult {\n batchUsed: boolean;\n batchErrors: number;\n}\n\nexport async function batchSyncInAppProducts(\n client: PlayApiClient,\n packageName: string,\n dir: string,\n options?: { dryRun?: boolean },\n): Promise<BatchSyncResult> {\n const localProducts = await readProductsFromDir(dir);\n\n if (localProducts.length === 0) {\n return { created: 0, updated: 0, unchanged: 0, skus: [], batchUsed: false, batchErrors: 0 };\n }\n\n const response = await client.inappproducts.list(packageName);\n const remoteSkus = new Set((response.inappproduct || []).map((p) => p.sku));\n\n const toUpdate = localProducts.filter((p) => remoteSkus.has(p.sku));\n const toCreate = localProducts.filter((p) => !remoteSkus.has(p.sku));\n const skus = localProducts.map((p) => p.sku);\n\n if (options?.dryRun) {\n return {\n created: toCreate.length,\n updated: toUpdate.length,\n unchanged: 0,\n skus,\n batchUsed: toUpdate.length > 1,\n batchErrors: 0,\n };\n }\n\n let batchUsed = false;\n let batchErrors = 0;\n\n if (toUpdate.length > 1) {\n batchUsed = true;\n try {\n await batchUpdateProducts(client, packageName, toUpdate);\n } catch {\n batchErrors++;\n // Fallback to serial updates\n for (const product of toUpdate) {\n await client.inappproducts.update(packageName, product.sku, product);\n }\n }\n } else {\n for (const product of toUpdate) {\n await client.inappproducts.update(packageName, product.sku, product);\n }\n }\n\n for (const product of toCreate) {\n await client.inappproducts.create(packageName, product);\n }\n\n return {\n created: toCreate.length,\n updated: toUpdate.length,\n unchanged: 0,\n skus,\n batchUsed,\n batchErrors,\n };\n}\n","import type {\n PlayApiClient,\n ProductPurchase,\n ProductPurchaseV2,\n SubscriptionPurchaseV2,\n SubscriptionDeferResponse,\n SubscriptionsV2DeferResponse,\n Order,\n} from \"@gpc-cli/api\";\nimport { validatePackageName } from \"../utils/validation.js\";\nimport { GpcError } from \"../errors.js\";\n\nexport async function getProductPurchase(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n token: string,\n): Promise<ProductPurchase> {\n validatePackageName(packageName);\n return client.purchases.getProduct(packageName, productId, token);\n}\n\nexport async function acknowledgeProductPurchase(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n token: string,\n payload?: string,\n): Promise<void> {\n validatePackageName(packageName);\n const body = payload ? { developerPayload: payload } : undefined;\n return client.purchases.acknowledgeProduct(packageName, productId, token, body);\n}\n\nexport async function consumeProductPurchase(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n token: string,\n): Promise<void> {\n validatePackageName(packageName);\n return client.purchases.consumeProduct(packageName, productId, token);\n}\n\nexport async function getSubscriptionPurchase(\n client: PlayApiClient,\n packageName: string,\n token: string,\n): Promise<SubscriptionPurchaseV2> {\n validatePackageName(packageName);\n return client.purchases.getSubscriptionV2(packageName, token);\n}\n\nexport async function cancelSubscriptionPurchase(\n client: PlayApiClient,\n packageName: string,\n subscriptionId: string,\n token: string,\n): Promise<void> {\n validatePackageName(packageName);\n return client.purchases.cancelSubscription(packageName, subscriptionId, token);\n}\n\nexport async function deferSubscriptionPurchase(\n client: PlayApiClient,\n packageName: string,\n subscriptionId: string,\n token: string,\n desiredExpiry: string,\n): Promise<SubscriptionDeferResponse> {\n validatePackageName(packageName);\n const sub = await client.purchases.getSubscriptionV1(packageName, subscriptionId, token);\n return client.purchases.deferSubscription(packageName, subscriptionId, token, {\n deferralInfo: {\n expectedExpiryTimeMillis: sub.expiryTimeMillis,\n desiredExpiryTimeMillis: String(new Date(desiredExpiry).getTime()),\n },\n });\n}\n\nexport async function revokeSubscriptionPurchase(\n client: PlayApiClient,\n packageName: string,\n token: string,\n): Promise<void> {\n validatePackageName(packageName);\n return client.purchases.revokeSubscriptionV2(packageName, token);\n}\n\nexport async function refundSubscriptionV2(\n client: PlayApiClient,\n packageName: string,\n token: string,\n): Promise<void> {\n validatePackageName(packageName);\n return client.purchases.refundSubscriptionV2(packageName, token);\n}\n\nimport type { VoidedPurchase } from \"@gpc-cli/api\";\nimport { paginateAll } from \"@gpc-cli/api\";\n\nexport interface ListVoidedOptions {\n startTime?: string;\n endTime?: string;\n type?: number;\n includeQuantityBasedPartialRefund?: boolean;\n maxResults?: number;\n limit?: number;\n nextPage?: string;\n}\n\nexport async function listVoidedPurchases(\n client: PlayApiClient,\n packageName: string,\n options?: ListVoidedOptions,\n): Promise<{ voidedPurchases: VoidedPurchase[]; nextPageToken?: string }> {\n validatePackageName(packageName);\n if (options?.limit || options?.nextPage) {\n const result = await paginateAll<VoidedPurchase>(\n async (pageToken) => {\n const resp = await client.purchases.listVoided(packageName, {\n startTime: options?.startTime,\n endTime: options?.endTime,\n type: options?.type,\n includeQuantityBasedPartialRefund: options?.includeQuantityBasedPartialRefund,\n maxResults: options?.maxResults,\n token: pageToken,\n });\n return {\n items: resp.voidedPurchases || [],\n nextPageToken: resp.tokenPagination?.nextPageToken,\n };\n },\n { limit: options.limit, startPageToken: options.nextPage },\n );\n return { voidedPurchases: result.items, nextPageToken: result.nextPageToken };\n }\n return client.purchases.listVoided(packageName, options);\n}\n\nexport async function refundOrder(\n client: PlayApiClient,\n packageName: string,\n orderId: string,\n options?: { fullRefund?: boolean; proratedRefund?: boolean },\n): Promise<void> {\n validatePackageName(packageName);\n return client.orders.refund(packageName, orderId, options);\n}\n\n// --- Orders API (May 2025) ---\n\nexport async function getOrderDetails(\n client: PlayApiClient,\n packageName: string,\n orderId: string,\n): Promise<Order> {\n validatePackageName(packageName);\n return client.orders.get(packageName, orderId);\n}\n\nexport async function batchGetOrders(\n client: PlayApiClient,\n packageName: string,\n orderIds: string[],\n): Promise<Order[]> {\n validatePackageName(packageName);\n if (orderIds.length === 0) {\n throw new GpcError(\"No order IDs provided\", \"ORDERS_BATCH_EMPTY\", 2, \"Pass at least one order ID with --ids\");\n }\n if (orderIds.length > 1000) {\n throw new GpcError(`Too many order IDs (${orderIds.length}). Maximum is 1000.`, \"ORDERS_BATCH_LIMIT\", 2, \"Split into multiple requests of 1000 or fewer\");\n }\n return client.orders.batchGet(packageName, orderIds);\n}\n\n// --- ProductPurchaseV2 (Jun 2025) ---\n\nexport async function getProductPurchaseV2(\n client: PlayApiClient,\n packageName: string,\n token: string,\n): Promise<ProductPurchaseV2> {\n validatePackageName(packageName);\n return client.purchases.getProductV2(packageName, token);\n}\n\n// --- SubscriptionsV2 cancel/defer (Sep 2025 / Jan 2026) ---\n\nexport async function cancelSubscriptionV2(\n client: PlayApiClient,\n packageName: string,\n token: string,\n cancellationType?: string,\n): Promise<void> {\n validatePackageName(packageName);\n const body = cancellationType ? { cancellationType } : undefined;\n return client.purchases.cancelSubscriptionV2(packageName, token, body);\n}\n\nexport async function deferSubscriptionV2(\n client: PlayApiClient,\n packageName: string,\n token: string,\n desiredExpiryTime: string,\n): Promise<SubscriptionsV2DeferResponse> {\n validatePackageName(packageName);\n return client.purchases.deferSubscriptionV2(packageName, token, {\n deferralInfo: { desiredExpiryTime },\n });\n}\n","import type { PlayApiClient, ConvertRegionPricesResponse } from \"@gpc-cli/api\";\n\nexport async function convertRegionPrices(\n client: PlayApiClient,\n packageName: string,\n currencyCode: string,\n amount: string,\n): Promise<ConvertRegionPricesResponse> {\n const units = amount.split(\".\")[0] || \"0\";\n const fractional = amount.split(\".\")[1] || \"0\";\n const nanos = Number(fractional.padEnd(9, \"0\").slice(0, 9));\n\n return client.monetization.convertRegionPrices(packageName, {\n price: {\n currencyCode,\n units,\n nanos,\n },\n });\n}\n","import type { PlayApiClient, ReportBucket, ReportType, StatsDimension } from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\n\nconst FINANCIAL_REPORT_TYPES: ReadonlySet<string> = new Set([\n \"earnings\",\n \"sales\",\n \"estimated_sales\",\n \"play_balance\",\n]);\n\nconst STATS_REPORT_TYPES: ReadonlySet<string> = new Set([\n \"installs\",\n \"crashes\",\n \"ratings\",\n \"reviews\",\n \"store_performance\",\n \"subscriptions\",\n]);\n\nconst VALID_DIMENSIONS: ReadonlySet<string> = new Set([\n \"country\",\n \"language\",\n \"os_version\",\n \"device\",\n \"app_version\",\n \"carrier\",\n \"overview\",\n]);\n\nexport function isFinancialReportType(type: string): boolean {\n return FINANCIAL_REPORT_TYPES.has(type);\n}\n\nexport function isStatsReportType(type: string): boolean {\n return STATS_REPORT_TYPES.has(type);\n}\n\nexport function isValidReportType(type: string): type is ReportType {\n return FINANCIAL_REPORT_TYPES.has(type) || STATS_REPORT_TYPES.has(type);\n}\n\nexport function isValidStatsDimension(dim: string): dim is StatsDimension {\n return VALID_DIMENSIONS.has(dim);\n}\n\nexport interface ParsedMonth {\n year: number;\n month: number;\n}\n\nexport function parseMonth(monthStr: string): ParsedMonth {\n const match = /^(\\d{4})-(\\d{2})$/.exec(monthStr);\n if (!match) {\n throw new GpcError(\n `Invalid month format \"${monthStr}\". Expected YYYY-MM (e.g., 2026-03).`,\n \"REPORT_INVALID_MONTH\",\n 2,\n \"Use the format YYYY-MM, for example: --month 2026-03\",\n );\n }\n const year = Number(match[1]);\n const month = Number(match[2]);\n if (month < 1 || month > 12) {\n throw new GpcError(\n `Invalid month \"${month}\". Must be between 01 and 12.`,\n \"REPORT_INVALID_MONTH\",\n 2,\n \"The month value must be between 01 and 12.\",\n );\n }\n return { year, month };\n}\n\nexport async function listReports(\n _client: PlayApiClient,\n _packageName: string,\n reportType: ReportType,\n _year: number,\n _month: number,\n): Promise<ReportBucket[]> {\n throw new GpcError(\n `Report listing for \"${reportType}\" is not available through the Google Play Developer API.`,\n \"REPORT_NOT_SUPPORTED\",\n 1,\n isFinancialReportType(reportType)\n ? \"Financial reports are delivered via Google Cloud Storage. Access them from Play Console → Download reports → Financial.\"\n : \"Stats reports are delivered via Google Cloud Storage. For real-time metrics, use 'gpc vitals' commands.\",\n );\n}\n\nexport async function downloadReport(\n _client: PlayApiClient,\n _packageName: string,\n reportType: ReportType,\n _year: number,\n _month: number,\n): Promise<string> {\n throw new GpcError(\n `Report download for \"${reportType}\" is not available through the Google Play Developer API.`,\n \"REPORT_NOT_SUPPORTED\",\n 1,\n isFinancialReportType(reportType)\n ? \"Financial reports are delivered via Google Cloud Storage. Access them from Play Console → Download reports → Financial.\"\n : \"Stats reports are delivered via Google Cloud Storage. For real-time metrics, use 'gpc vitals' commands.\",\n );\n}\n","import type { UsersApiClient, User, DeveloperPermission, Grant } from \"@gpc-cli/api\";\nimport { paginateAll } from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\n\nexport const PERMISSION_PROPAGATION_WARNING =\n \"Note: Permission changes may take up to 48 hours to propagate.\";\n\nexport interface ListUsersOptions {\n pageToken?: string;\n pageSize?: number;\n limit?: number;\n nextPage?: string;\n}\n\nexport async function listUsers(\n client: UsersApiClient,\n developerId: string,\n options?: ListUsersOptions,\n): Promise<{ users: User[]; nextPageToken?: string }> {\n if (options?.limit || options?.nextPage) {\n const result = await paginateAll<User>(\n async (pageToken) => {\n const resp = await client.list(developerId, { pageToken, pageSize: options?.pageSize });\n return { items: resp.users || [], nextPageToken: resp.nextPageToken };\n },\n { limit: options.limit, startPageToken: options.nextPage },\n );\n return { users: result.items, nextPageToken: result.nextPageToken };\n }\n const response = await client.list(developerId, options);\n return { users: response.users || [], nextPageToken: response.nextPageToken };\n}\n\nexport async function getUser(\n client: UsersApiClient,\n developerId: string,\n userId: string,\n): Promise<User> {\n return client.get(developerId, userId);\n}\n\nexport async function inviteUser(\n client: UsersApiClient,\n developerId: string,\n email: string,\n permissions?: DeveloperPermission[],\n grants?: Grant[],\n): Promise<User> {\n const user: Partial<User> = { email };\n if (permissions) user.developerAccountPermission = permissions;\n if (grants) user.grants = grants;\n return client.create(developerId, user);\n}\n\nexport async function updateUser(\n client: UsersApiClient,\n developerId: string,\n userId: string,\n permissions?: DeveloperPermission[],\n grants?: Grant[],\n): Promise<User> {\n const updates: Partial<User> = {};\n const masks: string[] = [];\n\n if (permissions) {\n updates.developerAccountPermission = permissions;\n masks.push(\"developerAccountPermission\");\n }\n if (grants) {\n updates.grants = grants;\n masks.push(\"grants\");\n }\n\n const updateMask = masks.length > 0 ? masks.join(\",\") : undefined;\n return client.update(developerId, userId, updates, updateMask);\n}\n\nexport async function removeUser(\n client: UsersApiClient,\n developerId: string,\n userId: string,\n): Promise<void> {\n return client.delete(developerId, userId);\n}\n\nexport function parseGrantArg(grantStr: string): Grant {\n const colonIdx = grantStr.indexOf(\":\");\n if (colonIdx === -1) {\n throw new GpcError(\n `Invalid grant format \"${grantStr}\". Expected <packageName>:<PERMISSION>[,<PERMISSION>...]`,\n \"USER_INVALID_GRANT\",\n 2,\n \"Use the format: com.example.app:VIEW_APP_INFORMATION,MANAGE_STORE_LISTING\",\n );\n }\n const packageName = grantStr.slice(0, colonIdx);\n const perms = grantStr.slice(colonIdx + 1).split(\",\") as DeveloperPermission[];\n return { packageName, appLevelPermissions: perms };\n}\n","import type { UsersApiClient } from \"@gpc-cli/api\";\nimport type { Grant } from \"@gpc-cli/api\";\n\nexport async function listGrants(\n client: UsersApiClient,\n developerId: string,\n email: string,\n): Promise<Grant[]> {\n const result = await client.grants.list(developerId, email);\n return result.grants || [];\n}\n\nexport async function createGrant(\n client: UsersApiClient,\n developerId: string,\n email: string,\n packageName: string,\n permissions: string[],\n): Promise<Grant> {\n return client.grants.create(developerId, email, {\n packageName,\n appLevelPermissions: permissions as Grant[\"appLevelPermissions\"],\n });\n}\n\nexport async function updateGrant(\n client: UsersApiClient,\n developerId: string,\n email: string,\n packageName: string,\n permissions: string[],\n): Promise<Grant> {\n return client.grants.patch(\n developerId,\n email,\n packageName,\n {\n appLevelPermissions: permissions as Grant[\"appLevelPermissions\"],\n },\n \"appLevelPermissions\",\n );\n}\n\nexport async function deleteGrant(\n client: UsersApiClient,\n developerId: string,\n email: string,\n packageName: string,\n): Promise<void> {\n return client.grants.delete(developerId, email, packageName);\n}\n","import type { PlayApiClient, Testers } from \"@gpc-cli/api\";\nimport { readFile } from \"node:fs/promises\";\nimport { GpcError } from \"../errors.js\";\n\nexport async function listTesters(\n client: PlayApiClient,\n packageName: string,\n track: string,\n): Promise<Testers> {\n const edit = await client.edits.insert(packageName);\n try {\n const testers = await client.testers.get(packageName, edit.id, track);\n return testers;\n } finally {\n await client.edits.delete(packageName, edit.id);\n }\n}\n\nexport async function addTesters(\n client: PlayApiClient,\n packageName: string,\n track: string,\n groupEmails: string[],\n): Promise<Testers> {\n const edit = await client.edits.insert(packageName);\n try {\n const current = await client.testers.get(packageName, edit.id, track);\n const existing = new Set(current.googleGroups || []);\n for (const email of groupEmails) {\n existing.add(email.trim());\n }\n const updated = await client.testers.update(packageName, edit.id, track, {\n googleGroups: [...existing],\n });\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n return updated;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function removeTesters(\n client: PlayApiClient,\n packageName: string,\n track: string,\n groupEmails: string[],\n): Promise<Testers> {\n const edit = await client.edits.insert(packageName);\n try {\n const current = await client.testers.get(packageName, edit.id, track);\n const toRemove = new Set(groupEmails.map((e) => e.trim()));\n const filtered = (current.googleGroups || []).filter((g) => !toRemove.has(g));\n const updated = await client.testers.update(packageName, edit.id, track, {\n googleGroups: filtered,\n });\n await client.edits.validate(packageName, edit.id);\n await client.edits.commit(packageName, edit.id);\n return updated;\n } catch (error) {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n throw error;\n }\n}\n\nexport async function importTestersFromCsv(\n client: PlayApiClient,\n packageName: string,\n track: string,\n csvPath: string,\n): Promise<{ added: number; testers: Testers }> {\n const content = await readFile(csvPath, \"utf-8\");\n const emails = content\n .split(/[,\\n\\r]+/)\n .map((e) => e.trim())\n .filter((e) => e.length > 0 && e.includes(\"@\"));\n\n if (emails.length === 0) {\n throw new GpcError(\n `No valid email addresses found in ${csvPath}.`,\n \"TESTER_NO_EMAILS\",\n 1,\n \"The CSV file must contain email addresses separated by commas or newlines. Each email must contain an @ symbol.\",\n );\n }\n\n const testers = await addTesters(client, packageName, track, emails);\n return { added: emails.length, testers };\n}\n","import { execFile as execFileCb } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { GpcError } from \"../errors.js\";\n\nconst execFile = promisify(execFileCb);\n\nexport interface GitNotesOptions {\n since?: string;\n language?: string;\n maxLength?: number;\n}\n\nexport interface GitReleaseNotes {\n language: string;\n text: string;\n commitCount: number;\n since: string;\n truncated: boolean;\n}\n\ninterface ParsedCommit {\n type: string;\n message: string;\n}\n\nconst COMMIT_TYPE_HEADERS: Record<string, string> = {\n feat: \"New\",\n fix: \"Fixed\",\n perf: \"Improved\",\n};\n\nconst DEFAULT_MAX_LENGTH = 500;\n\nfunction parseConventionalCommit(subject: string): ParsedCommit {\n const match = subject.match(/^(\\w+)(?:\\([^)]*\\))?:\\s*(.+)$/);\n if (match) {\n return { type: match[1] ?? \"other\", message: (match[2] ?? \"\").trim() };\n }\n return { type: \"other\", message: subject.trim() };\n}\n\nfunction formatNotes(\n commits: ParsedCommit[],\n maxLength: number,\n): { text: string; truncated: boolean } {\n const groups = new Map<string, string[]>();\n\n for (const commit of commits) {\n const header = COMMIT_TYPE_HEADERS[commit.type] || \"Changes\";\n if (!groups.has(header)) {\n groups.set(header, []);\n }\n groups.get(header)?.push(commit.message);\n }\n\n // Order: New, Fixed, Improved, then Changes\n const order = [\"New\", \"Fixed\", \"Improved\", \"Changes\"];\n const sections: string[] = [];\n\n for (const header of order) {\n const items = groups.get(header);\n if (!items || items.length === 0) continue;\n const bullets = items.map((m) => `\\u2022 ${m}`).join(\"\\n\");\n sections.push(`${header}:\\n${bullets}`);\n }\n\n let text = sections.join(\"\\n\\n\");\n let truncated = false;\n\n if (text.length > maxLength) {\n text = text.slice(0, maxLength - 3) + \"...\";\n truncated = true;\n }\n\n return { text, truncated };\n}\n\nasync function gitExec(args: string[]): Promise<string> {\n try {\n const { stdout } = await execFile(\"git\", args);\n return stdout.trim();\n } catch (error: unknown) {\n const err = error as { code?: string; stderr?: string; message?: string };\n if (err.code === \"ENOENT\") {\n throw new GpcError(\n \"git is not available on this system\",\n \"GIT_NOT_FOUND\",\n 1,\n \"Install git and ensure it is in your PATH.\",\n );\n }\n throw error;\n }\n}\n\nexport async function generateNotesFromGit(options?: GitNotesOptions): Promise<GitReleaseNotes> {\n const language = options?.language || \"en-US\";\n const maxLength = options?.maxLength ?? DEFAULT_MAX_LENGTH;\n let since = options?.since;\n\n if (!since) {\n try {\n since = await gitExec([\"describe\", \"--tags\", \"--abbrev=0\"]);\n } catch (e) {\n if (e instanceof GpcError && e.code === \"GIT_NOT_FOUND\") throw e;\n throw new GpcError(\n \"No git tags found. Cannot determine commit range for release notes.\",\n \"GIT_NO_TAGS\",\n 1,\n \"Create a tag first (e.g., git tag v1.0.0) or use --since <ref> to specify a starting point.\",\n );\n }\n }\n\n let logOutput: string;\n try {\n logOutput = await gitExec([\"log\", `${since}..HEAD`, \"--format=%s\"]);\n } catch (error: unknown) {\n const err = error as { stderr?: string; message?: string };\n const msg = err.stderr || err.message || String(error);\n throw new GpcError(\n `Failed to read git log from \"${since}\": ${msg}`,\n \"GIT_LOG_FAILED\",\n 1,\n `Verify that \"${since}\" is a valid git ref (tag, branch, or SHA).`,\n );\n }\n\n if (!logOutput) {\n return {\n language,\n text: \"No changes since last release.\",\n commitCount: 0,\n since,\n truncated: false,\n };\n }\n\n const subjects = logOutput.split(\"\\n\").filter((line) => line.length > 0);\n const commits = subjects.map(parseConventionalCommit);\n const { text, truncated } = formatNotes(commits, maxLength);\n\n return {\n language,\n text,\n commitCount: subjects.length,\n since,\n truncated,\n };\n}\n","import type {\n PlayApiClient,\n AppRecoveryAction,\n AppRecoveryTargeting,\n CreateAppRecoveryActionRequest,\n} from \"@gpc-cli/api\";\n\nexport async function listRecoveryActions(\n client: PlayApiClient,\n packageName: string,\n versionCode?: number,\n): Promise<AppRecoveryAction[]> {\n return client.appRecovery.list(packageName, versionCode);\n}\n\nexport async function cancelRecoveryAction(\n client: PlayApiClient,\n packageName: string,\n recoveryId: string,\n): Promise<void> {\n return client.appRecovery.cancel(packageName, recoveryId);\n}\n\nexport async function deployRecoveryAction(\n client: PlayApiClient,\n packageName: string,\n recoveryId: string,\n): Promise<void> {\n return client.appRecovery.deploy(packageName, recoveryId);\n}\n\nexport async function createRecoveryAction(\n client: PlayApiClient,\n packageName: string,\n request: CreateAppRecoveryActionRequest,\n): Promise<AppRecoveryAction> {\n return client.appRecovery.create(packageName, request);\n}\n\nexport async function addRecoveryTargeting(\n client: PlayApiClient,\n packageName: string,\n actionId: string,\n targeting: AppRecoveryTargeting,\n): Promise<AppRecoveryAction> {\n return client.appRecovery.addTargeting(packageName, actionId, targeting);\n}\n","import type { PlayApiClient, DataSafety } from \"@gpc-cli/api\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { GpcError } from \"../errors.js\";\n\nexport async function getDataSafety(\n client: PlayApiClient,\n packageName: string,\n): Promise<DataSafety> {\n return client.dataSafety.get(packageName);\n}\n\nexport async function updateDataSafety(\n client: PlayApiClient,\n packageName: string,\n data: DataSafety,\n): Promise<DataSafety> {\n return client.dataSafety.update(packageName, data);\n}\n\nexport async function exportDataSafety(\n client: PlayApiClient,\n packageName: string,\n outputPath: string,\n): Promise<DataSafety> {\n const dataSafety = await getDataSafety(client, packageName);\n await writeFile(outputPath, JSON.stringify(dataSafety, null, 2) + \"\\n\", \"utf-8\");\n return dataSafety;\n}\n\nexport async function importDataSafety(\n client: PlayApiClient,\n packageName: string,\n filePath: string,\n): Promise<DataSafety> {\n const content = await readFile(filePath, \"utf-8\");\n let data: DataSafety;\n try {\n data = JSON.parse(content) as DataSafety;\n } catch {\n throw new GpcError(\n `Failed to parse data safety JSON from \"${filePath}\"`,\n \"INVALID_JSON\",\n 1,\n \"Ensure the file contains valid JSON matching the data safety schema.\",\n );\n }\n return updateDataSafety(client, packageName, data);\n}\n","import type { PlayApiClient, ExternalTransaction, ExternalTransactionRefund } from \"@gpc-cli/api\";\n\nexport async function createExternalTransaction(\n client: PlayApiClient,\n packageName: string,\n data: ExternalTransaction,\n): Promise<ExternalTransaction> {\n return client.externalTransactions.create(packageName, data);\n}\n\nexport async function getExternalTransaction(\n client: PlayApiClient,\n packageName: string,\n transactionId: string,\n): Promise<ExternalTransaction> {\n return client.externalTransactions.get(packageName, transactionId);\n}\n\nexport async function refundExternalTransaction(\n client: PlayApiClient,\n packageName: string,\n transactionId: string,\n refundData: ExternalTransactionRefund,\n): Promise<ExternalTransaction> {\n return client.externalTransactions.refund(packageName, transactionId, refundData);\n}\n","import type { PlayApiClient, DeviceTierConfig } from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\n\nexport async function listDeviceTiers(\n client: PlayApiClient,\n packageName: string,\n): Promise<DeviceTierConfig[]> {\n if (!packageName) {\n throw new GpcError(\n \"Package name is required\",\n \"MISSING_PACKAGE_NAME\",\n 2,\n \"Provide a package name with --app or set it in config.\",\n );\n }\n return client.deviceTiers.list(packageName);\n}\n\nexport async function getDeviceTier(\n client: PlayApiClient,\n packageName: string,\n configId: string,\n): Promise<DeviceTierConfig> {\n if (!packageName) {\n throw new GpcError(\n \"Package name is required\",\n \"MISSING_PACKAGE_NAME\",\n 2,\n \"Provide a package name with --app or set it in config.\",\n );\n }\n if (!configId) {\n throw new GpcError(\n \"Config ID is required\",\n \"MISSING_CONFIG_ID\",\n 2,\n \"Provide a device tier config ID.\",\n );\n }\n return client.deviceTiers.get(packageName, configId);\n}\n\nexport async function createDeviceTier(\n client: PlayApiClient,\n packageName: string,\n config: DeviceTierConfig,\n): Promise<DeviceTierConfig> {\n if (!packageName) {\n throw new GpcError(\n \"Package name is required\",\n \"MISSING_PACKAGE_NAME\",\n 2,\n \"Provide a package name with --app or set it in config.\",\n );\n }\n if (!config || !config.deviceGroups || config.deviceGroups.length === 0) {\n throw new GpcError(\n \"Device tier config must include at least one device group\",\n \"INVALID_DEVICE_TIER_CONFIG\",\n 2,\n \"Provide a valid config with deviceGroups.\",\n );\n }\n return client.deviceTiers.create(packageName, config);\n}\n","import type {\n PlayApiClient,\n OneTimeProduct,\n OneTimeProductsListResponse,\n OneTimeOffer,\n OneTimeOffersListResponse,\n} from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\n\nexport async function listOneTimeProducts(\n client: PlayApiClient,\n packageName: string,\n): Promise<OneTimeProductsListResponse> {\n try {\n return await client.oneTimeProducts.list(packageName);\n } catch (error) {\n throw new GpcError(\n `Failed to list one-time products: ${error instanceof Error ? error.message : String(error)}`,\n \"OTP_LIST_FAILED\",\n 4,\n \"Check your package name and API credentials.\",\n );\n }\n}\n\nexport async function getOneTimeProduct(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n): Promise<OneTimeProduct> {\n try {\n return await client.oneTimeProducts.get(packageName, productId);\n } catch (error) {\n throw new GpcError(\n `Failed to get one-time product \"${productId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"OTP_GET_FAILED\",\n 4,\n \"Check that the product ID exists.\",\n );\n }\n}\n\nexport async function createOneTimeProduct(\n client: PlayApiClient,\n packageName: string,\n data: OneTimeProduct,\n): Promise<OneTimeProduct> {\n try {\n return await client.oneTimeProducts.create(packageName, data);\n } catch (error) {\n throw new GpcError(\n `Failed to create one-time product: ${error instanceof Error ? error.message : String(error)}`,\n \"OTP_CREATE_FAILED\",\n 4,\n \"Verify the product data and ensure the product ID is unique.\",\n );\n }\n}\n\nconst OTP_ID_FIELDS = new Set([\"productId\", \"packageName\"]);\n\nfunction deriveOtpUpdateMask(data: Partial<OneTimeProduct>): string {\n return Object.keys(data)\n .filter((k) => !OTP_ID_FIELDS.has(k))\n .join(\",\");\n}\n\nconst OTP_OFFER_ID_FIELDS = new Set([\"productId\", \"offerId\"]);\n\nfunction deriveOtpOfferUpdateMask(data: Partial<OneTimeOffer>): string {\n return Object.keys(data)\n .filter((k) => !OTP_OFFER_ID_FIELDS.has(k))\n .join(\",\");\n}\n\nexport async function updateOneTimeProduct(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n data: Partial<OneTimeProduct>,\n updateMask?: string,\n): Promise<OneTimeProduct> {\n try {\n const mask = updateMask || deriveOtpUpdateMask(data);\n return await client.oneTimeProducts.update(packageName, productId, data, mask);\n } catch (error) {\n throw new GpcError(\n `Failed to update one-time product \"${productId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"OTP_UPDATE_FAILED\",\n 4,\n \"Check that the product ID exists and the data is valid.\",\n );\n }\n}\n\nexport async function deleteOneTimeProduct(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n): Promise<void> {\n try {\n await client.oneTimeProducts.delete(packageName, productId);\n } catch (error) {\n throw new GpcError(\n `Failed to delete one-time product \"${productId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"OTP_DELETE_FAILED\",\n 4,\n \"Check that the product ID exists and is not active.\",\n );\n }\n}\n\nexport async function listOneTimeOffers(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n): Promise<OneTimeOffersListResponse> {\n try {\n return await client.oneTimeProducts.listOffers(packageName, productId);\n } catch (error) {\n throw new GpcError(\n `Failed to list offers for product \"${productId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"OTP_OFFERS_LIST_FAILED\",\n 4,\n \"Check the product ID and your API credentials.\",\n );\n }\n}\n\nexport async function getOneTimeOffer(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n offerId: string,\n): Promise<OneTimeOffer> {\n try {\n return await client.oneTimeProducts.getOffer(packageName, productId, offerId);\n } catch (error) {\n throw new GpcError(\n `Failed to get offer \"${offerId}\" for product \"${productId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"OTP_OFFER_GET_FAILED\",\n 4,\n \"Check that the product and offer IDs exist.\",\n );\n }\n}\n\nexport async function createOneTimeOffer(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n data: OneTimeOffer,\n): Promise<OneTimeOffer> {\n try {\n return await client.oneTimeProducts.createOffer(packageName, productId, data);\n } catch (error) {\n throw new GpcError(\n `Failed to create offer for product \"${productId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"OTP_OFFER_CREATE_FAILED\",\n 4,\n \"Verify the offer data and ensure the offer ID is unique.\",\n );\n }\n}\n\nexport async function updateOneTimeOffer(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n offerId: string,\n data: Partial<OneTimeOffer>,\n updateMask?: string,\n): Promise<OneTimeOffer> {\n try {\n const mask = updateMask || deriveOtpOfferUpdateMask(data);\n return await client.oneTimeProducts.updateOffer(packageName, productId, offerId, data, mask);\n } catch (error) {\n throw new GpcError(\n `Failed to update offer \"${offerId}\" for product \"${productId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"OTP_OFFER_UPDATE_FAILED\",\n 4,\n \"Check that the product and offer IDs exist and the data is valid.\",\n );\n }\n}\n\nexport interface OneTimeProductDiff {\n field: string;\n local: string;\n remote: string;\n}\n\nexport async function diffOneTimeProduct(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n localData: OneTimeProduct,\n): Promise<OneTimeProductDiff[]> {\n const remote = await client.oneTimeProducts.get(packageName, productId);\n const diffs: OneTimeProductDiff[] = [];\n const fieldsToCompare = [\"listings\", \"purchaseType\", \"taxAndComplianceSettings\"];\n\n for (const field of fieldsToCompare) {\n const localVal = JSON.stringify(\n (localData as unknown as Record<string, unknown>)[field] ?? null,\n );\n const remoteVal = JSON.stringify((remote as unknown as Record<string, unknown>)[field] ?? null);\n if (localVal !== remoteVal) {\n diffs.push({ field, local: localVal, remote: remoteVal });\n }\n }\n return diffs;\n}\n\nexport async function deleteOneTimeOffer(\n client: PlayApiClient,\n packageName: string,\n productId: string,\n offerId: string,\n): Promise<void> {\n try {\n await client.oneTimeProducts.deleteOffer(packageName, productId, offerId);\n } catch (error) {\n throw new GpcError(\n `Failed to delete offer \"${offerId}\" for product \"${productId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"OTP_OFFER_DELETE_FAILED\",\n 4,\n \"Check that the product and offer IDs exist.\",\n );\n }\n}\n","import process from \"node:process\";\n\nconst FRAMES = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\nconst INTERVAL_MS = 80;\n\nexport interface Spinner {\n start(): void;\n stop(message?: string): void;\n fail(message?: string): void;\n update(message: string): void;\n}\n\nexport function createSpinner(message: string): Spinner {\n const isTTY = process.stderr.isTTY === true;\n let frameIndex = 0;\n let timer: ReturnType<typeof setInterval> | undefined;\n let currentMessage = message;\n let started = false;\n\n function clearLine(): void {\n if (isTTY) {\n process.stderr.write(\"\\r\\x1b[K\");\n }\n }\n\n function renderFrame(): void {\n const frame = FRAMES[frameIndex % FRAMES.length];\n process.stderr.write(`\\r\\x1b[K${frame} ${currentMessage}`);\n frameIndex++;\n }\n\n return {\n start(): void {\n if (started) return;\n started = true;\n\n if (!isTTY) {\n process.stderr.write(`${currentMessage}\\n`);\n return;\n }\n\n renderFrame();\n timer = setInterval(renderFrame, INTERVAL_MS);\n },\n\n stop(msg?: string): void {\n if (timer) {\n clearInterval(timer);\n timer = undefined;\n }\n const text = msg ?? currentMessage;\n if (isTTY) {\n clearLine();\n process.stderr.write(`\\u2714 ${text}\\n`);\n } else if (!started) {\n process.stderr.write(`${text}\\n`);\n }\n started = false;\n },\n\n fail(msg?: string): void {\n if (timer) {\n clearInterval(timer);\n timer = undefined;\n }\n const text = msg ?? currentMessage;\n if (isTTY) {\n clearLine();\n process.stderr.write(`\\u2718 ${text}\\n`);\n } else if (!started) {\n process.stderr.write(`${text}\\n`);\n }\n started = false;\n },\n\n update(msg: string): void {\n currentMessage = msg;\n if (!isTTY || !started) return;\n renderFrame();\n },\n };\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { getCacheDir } from \"@gpc-cli/config\";\n\nexport interface TrainStage {\n track: string;\n rollout: number;\n /** ISO 8601 duration or human string like \"2d\", \"7d\" */\n after?: string;\n}\n\nexport interface TrainGates {\n crashes?: { max: number };\n anr?: { max: number };\n}\n\nexport interface TrainConfig {\n stages: TrainStage[];\n gates?: TrainGates;\n}\n\nexport type TrainStatus = \"idle\" | \"running\" | \"paused\" | \"completed\" | \"aborted\";\n\nexport interface TrainState {\n packageName: string;\n status: TrainStatus;\n currentStage: number;\n startedAt?: string;\n updatedAt: string;\n stages: Array<\n TrainStage & {\n executedAt?: string;\n scheduledAt?: string;\n }\n >;\n gates?: TrainGates;\n}\n\nfunction stateFile(packageName: string): string {\n return join(getCacheDir(), `train-${packageName}.json`);\n}\n\nexport async function readTrainState(packageName: string): Promise<TrainState | null> {\n const path = stateFile(packageName);\n try {\n const raw = await readFile(path, \"utf-8\");\n return JSON.parse(raw) as TrainState;\n } catch {\n return null;\n }\n}\n\nexport async function writeTrainState(packageName: string, state: TrainState): Promise<void> {\n const path = stateFile(packageName);\n const dir = dirname(path);\n await mkdir(dir, { recursive: true });\n await writeFile(path, JSON.stringify(state, null, 2), \"utf-8\");\n}\n\nexport async function clearTrainState(packageName: string): Promise<void> {\n const { unlink } = await import(\"node:fs/promises\");\n const path = stateFile(packageName);\n await unlink(path).catch(() => {});\n}\n\n/** Parse a duration string like \"2d\", \"7d\", \"1h\" into milliseconds. */\nexport function parseDuration(s: string): number {\n const match = /^(\\d+)(d|h|m)$/.exec(s.trim());\n if (!match) return 0;\n const n = parseInt(match[1] ?? \"0\", 10);\n switch (match[2]) {\n case \"d\":\n return n * 24 * 60 * 60 * 1000;\n case \"h\":\n return n * 60 * 60 * 1000;\n case \"m\":\n return n * 60 * 1000;\n default:\n return 0;\n }\n}\n","import type { PlayApiClient } from \"@gpc-cli/api\";\nimport type { ReportingApiClient } from \"@gpc-cli/api\";\nimport {\n readTrainState,\n writeTrainState,\n clearTrainState,\n parseDuration,\n} from \"../utils/train-state.js\";\nimport type { TrainConfig, TrainState } from \"../utils/train-state.js\";\nimport { updateRollout } from \"./releases.js\";\nimport { getVitalsCrashes, getVitalsAnr } from \"./vitals.js\";\nimport { GpcError } from \"../errors.js\";\n\nexport type { TrainConfig, TrainState };\n\nexport interface StartTrainOptions {\n force?: boolean;\n}\n\n/** Start or resume a release train for a package. */\nexport async function startTrain(\n apiClient: PlayApiClient,\n packageName: string,\n config: TrainConfig,\n options?: StartTrainOptions,\n): Promise<TrainState> {\n const existing = await readTrainState(packageName);\n\n if (existing && existing.status === \"running\" && !options?.force) {\n return existing;\n }\n\n const now = new Date().toISOString();\n const state: TrainState = {\n packageName,\n status: \"running\",\n currentStage: 0,\n startedAt: now,\n updatedAt: now,\n stages: config.stages.map((s, i) => ({\n ...s,\n scheduledAt: i === 0 ? now : undefined,\n })),\n gates: config.gates,\n };\n\n await writeTrainState(packageName, state);\n\n // Execute stage 0 immediately\n await executeStage(apiClient, packageName, state, 0);\n\n return state;\n}\n\n/** Get current train status. */\nexport async function getTrainStatus(packageName: string): Promise<TrainState | null> {\n return readTrainState(packageName);\n}\n\n/** Pause a running train. */\nexport async function pauseTrain(packageName: string): Promise<TrainState | null> {\n const state = await readTrainState(packageName);\n if (!state || state.status !== \"running\") return state;\n\n state.status = \"paused\";\n state.updatedAt = new Date().toISOString();\n await writeTrainState(packageName, state);\n return state;\n}\n\n/** Abort a train and clear state. */\nexport async function abortTrain(packageName: string): Promise<void> {\n await clearTrainState(packageName);\n}\n\n/** Advance the train to the next eligible stage. */\nexport async function advanceTrain(\n apiClient: PlayApiClient,\n reportingClient: ReportingApiClient,\n packageName: string,\n): Promise<TrainState | null> {\n const state = await readTrainState(packageName);\n if (!state || state.status !== \"running\") return state;\n\n const nextStage = state.currentStage + 1;\n if (nextStage >= state.stages.length) {\n state.status = \"completed\";\n state.updatedAt = new Date().toISOString();\n await writeTrainState(packageName, state);\n return state;\n }\n\n const nextStageConfig = state.stages[nextStage];\n if (!nextStageConfig) return state;\n\n // Check `after` delay\n if (nextStageConfig.after) {\n const delayMs = parseDuration(nextStageConfig.after);\n const currentStageConfig = state.stages[state.currentStage];\n const executedAt = currentStageConfig?.executedAt;\n if (executedAt && delayMs > 0) {\n const elapsed = Date.now() - new Date(executedAt).getTime();\n if (elapsed < delayMs) {\n // Not ready yet — schedule time for info\n const readyAt = new Date(new Date(executedAt).getTime() + delayMs).toISOString();\n nextStageConfig.scheduledAt = readyAt;\n await writeTrainState(packageName, state);\n return state;\n }\n }\n }\n\n // Check vitals gates before advancing\n if (state.gates) {\n if (state.gates.crashes?.max !== undefined) {\n const result = await getVitalsCrashes(reportingClient, packageName, { days: 1 });\n const latestRow = result.rows?.[result.rows.length - 1];\n const firstMetric = latestRow?.metrics ? Object.keys(latestRow.metrics)[0] : undefined;\n const value = firstMetric\n ? Number(latestRow?.metrics[firstMetric]?.decimalValue?.value)\n : undefined;\n if (value !== undefined && value > state.gates.crashes.max / 100) {\n state.status = \"paused\";\n state.updatedAt = new Date().toISOString();\n await writeTrainState(packageName, state);\n throw new GpcError(\n `Crash gate failed: ${(value * 100).toFixed(3)}% > max ${state.gates.crashes.max}%. Train paused.`,\n \"TRAIN_CRASH_GATE_FAILED\",\n 6,\n \"Review crash data with: gpc vitals crashes --days 1\",\n );\n }\n }\n\n if (state.gates.anr?.max !== undefined) {\n const result = await getVitalsAnr(reportingClient, packageName, { days: 1 });\n const latestRow = result.rows?.[result.rows.length - 1];\n const firstMetric = latestRow?.metrics ? Object.keys(latestRow.metrics)[0] : undefined;\n const value = firstMetric\n ? Number(latestRow?.metrics[firstMetric]?.decimalValue?.value)\n : undefined;\n if (value !== undefined && value > state.gates.anr.max / 100) {\n state.status = \"paused\";\n state.updatedAt = new Date().toISOString();\n await writeTrainState(packageName, state);\n throw new GpcError(\n `ANR gate failed: ${(value * 100).toFixed(3)}% > max ${state.gates.anr.max}%. Train paused.`,\n \"TRAIN_ANR_GATE_FAILED\",\n 6,\n \"Review ANR data with: gpc vitals anr --days 1\",\n );\n }\n }\n }\n\n await executeStage(apiClient, packageName, state, nextStage);\n return state;\n}\n\nasync function executeStage(\n apiClient: PlayApiClient,\n packageName: string,\n state: TrainState,\n stageIndex: number,\n): Promise<void> {\n const stage = state.stages[stageIndex];\n if (!stage) throw new GpcError(`Stage ${stageIndex} not found`, \"TRAIN_STAGE_NOT_FOUND\", 1, \"Check your release train configuration.\");\n const rolloutFraction = stage.rollout / 100;\n\n await updateRollout(apiClient, packageName, stage.track, \"increase\", rolloutFraction);\n\n stage.executedAt = new Date().toISOString();\n state.currentStage = stageIndex;\n state.updatedAt = new Date().toISOString();\n await writeTrainState(packageName, state);\n}\n","import type { GamesApiClient, Leaderboard, Achievement, GameEvent } from \"@gpc-cli/api\";\n\nexport { Leaderboard, Achievement, GameEvent };\n\nexport async function listLeaderboards(\n client: GamesApiClient,\n packageName: string,\n): Promise<Leaderboard[]> {\n const result = await client.leaderboards.list(packageName);\n return result.items ?? [];\n}\n\nexport async function listAchievements(\n client: GamesApiClient,\n packageName: string,\n): Promise<Achievement[]> {\n const result = await client.achievements.list(packageName);\n return result.items ?? [];\n}\n\nexport async function listEvents(\n client: GamesApiClient,\n packageName: string,\n): Promise<GameEvent[]> {\n const result = await client.events.list(packageName);\n return result.items ?? [];\n}\n","import type { EnterpriseApiClient, CustomApp } from \"@gpc-cli/api\";\n\nexport { CustomApp };\n\nexport async function listEnterpriseApps(\n client: EnterpriseApiClient,\n organizationId: string,\n): Promise<CustomApp[]> {\n const result = await client.apps.list(organizationId);\n return result.customApps ?? [];\n}\n\nexport async function createEnterpriseApp(\n client: EnterpriseApiClient,\n organizationId: string,\n app: Partial<CustomApp>,\n): Promise<CustomApp> {\n return client.apps.create(organizationId, app);\n}\n","import { appendFile, chmod, mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport interface AuditEntry {\n timestamp: string;\n command: string;\n app?: string;\n args: Record<string, unknown>;\n user?: string;\n success?: boolean;\n durationMs?: number;\n error?: string;\n}\n\nlet auditDir: string | null = null;\n\n/**\n * Initialize audit logging with a directory path.\n * Typically ~/.config/gpc/ or the XDG config dir.\n */\nexport function initAudit(configDir: string): void {\n auditDir = configDir;\n}\n\n/**\n * Write an audit log entry. Non-blocking — errors are silently ignored.\n */\nexport async function writeAuditLog(entry: AuditEntry): Promise<void> {\n if (!auditDir) return;\n\n try {\n await mkdir(auditDir, { recursive: true, mode: 0o700 });\n const logPath = join(auditDir, \"audit.log\");\n const redactedEntry = redactAuditArgs(entry);\n const line = JSON.stringify(redactedEntry) + \"\\n\";\n await appendFile(logPath, line, { encoding: \"utf-8\", mode: 0o600 });\n await chmod(logPath, 0o600).catch(() => {});\n } catch {\n // Audit logging must never break the CLI\n }\n}\n\nconst SENSITIVE_ARG_KEYS = new Set([\n \"keyFile\",\n \"key_file\",\n \"serviceAccount\",\n \"service-account\",\n \"token\",\n \"password\",\n \"secret\",\n \"credentials\",\n \"private_key\",\n \"privateKey\",\n \"private_key_id\",\n \"privateKeyId\",\n \"client_secret\",\n \"clientSecret\",\n \"accessToken\",\n \"access_token\",\n \"refreshToken\",\n \"refresh_token\",\n \"apiKey\",\n \"api_key\",\n \"auth_token\",\n \"bearer\",\n \"jwt\",\n \"signing_key\",\n \"keystore_password\",\n \"store_password\",\n \"key_password\",\n]);\n\nexport { SENSITIVE_ARG_KEYS };\n\nexport function redactAuditArgs(entry: AuditEntry): AuditEntry {\n const redacted: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(entry.args)) {\n redacted[k] = SENSITIVE_ARG_KEYS.has(k) ? \"[REDACTED]\" : v;\n }\n return { ...entry, args: redacted };\n}\n\n/**\n * Convenience: create an audit entry for a write command.\n */\nexport function createAuditEntry(\n command: string,\n args: Record<string, unknown>,\n app?: string,\n): AuditEntry {\n return {\n timestamp: new Date().toISOString(),\n command,\n app,\n args,\n };\n}\n\nexport async function listAuditEvents(options?: {\n limit?: number;\n since?: string;\n command?: string;\n}): Promise<AuditEntry[]> {\n if (!auditDir) return [];\n const logPath = join(auditDir, \"audit.log\");\n let content: string;\n try {\n content = await readFile(logPath, \"utf-8\");\n } catch {\n return [];\n }\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n let entries: AuditEntry[] = [];\n for (const line of lines) {\n try {\n entries.push(JSON.parse(line) as AuditEntry);\n } catch {\n // skip malformed lines\n }\n }\n if (options?.since) {\n const sinceDate = new Date(options.since).getTime();\n entries = entries.filter((e) => new Date(e.timestamp).getTime() >= sinceDate);\n }\n if (options?.command) {\n const cmd = options.command.toLowerCase();\n entries = entries.filter((e) => e.command.toLowerCase().includes(cmd));\n }\n if (options?.limit) {\n entries = entries.slice(-options.limit);\n }\n return entries;\n}\n\nexport async function searchAuditEvents(query: string): Promise<AuditEntry[]> {\n const all = await listAuditEvents();\n const q = query.toLowerCase();\n return all.filter((e) => {\n const text = JSON.stringify(e).toLowerCase();\n return text.includes(q);\n });\n}\n\nexport async function clearAuditLog(options?: {\n before?: string;\n dryRun?: boolean;\n}): Promise<{ deleted: number; remaining: number }> {\n if (!auditDir) return { deleted: 0, remaining: 0 };\n const logPath = join(auditDir, \"audit.log\");\n let content: string;\n try {\n content = await readFile(logPath, \"utf-8\");\n } catch {\n return { deleted: 0, remaining: 0 };\n }\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n if (!options?.before) {\n const count = lines.length;\n if (!options?.dryRun) {\n await writeFile(logPath, \"\", { encoding: \"utf-8\", mode: 0o600 });\n }\n return { deleted: count, remaining: 0 };\n }\n const beforeDate = new Date(options.before).getTime();\n const keep: string[] = [];\n const remove: string[] = [];\n for (const line of lines) {\n try {\n const entry = JSON.parse(line) as AuditEntry;\n if (new Date(entry.timestamp).getTime() < beforeDate) {\n remove.push(line);\n } else {\n keep.push(line);\n }\n } catch {\n keep.push(line);\n }\n }\n if (!options?.dryRun) {\n await writeFile(logPath, keep.length > 0 ? keep.join(\"\\n\") + \"\\n\" : \"\", {\n encoding: \"utf-8\",\n mode: 0o600,\n });\n }\n return { deleted: remove.length, remaining: keep.length };\n}\n","import { listAuditEvents } from \"../audit.js\";\n\nexport interface QuotaUsage {\n dailyCallsUsed: number;\n dailyCallsLimit: number;\n dailyCallsRemaining: number;\n minuteCallsUsed: number;\n minuteCallsLimit: number;\n minuteCallsRemaining: number;\n topCommands: Array<{ command: string; count: number }>;\n}\n\nconst DAILY_LIMIT = 200_000;\nconst MINUTE_LIMIT = 3_000;\n\n/** Compute quota usage from the local audit log. */\nexport async function getQuotaUsage(): Promise<QuotaUsage> {\n const now = Date.now();\n const startOfDay = new Date(now);\n startOfDay.setUTCHours(0, 0, 0, 0);\n\n const startOfMinute = new Date(now - 60 * 1000);\n\n const todayEntries = await listAuditEvents({\n since: startOfDay.toISOString(),\n });\n\n const minuteEntries = todayEntries.filter(\n (e) => new Date(e.timestamp).getTime() >= startOfMinute.getTime(),\n );\n\n const commandCounts = new Map<string, number>();\n for (const entry of todayEntries) {\n commandCounts.set(entry.command, (commandCounts.get(entry.command) ?? 0) + 1);\n }\n\n const topCommands = Array.from(commandCounts.entries())\n .map(([command, count]) => ({ command, count }))\n .sort((a, b) => b.count - a.count)\n .slice(0, 10);\n\n const dailyCallsUsed = todayEntries.length;\n const minuteCallsUsed = minuteEntries.length;\n\n return {\n dailyCallsUsed,\n dailyCallsLimit: DAILY_LIMIT,\n dailyCallsRemaining: Math.max(0, DAILY_LIMIT - dailyCallsUsed),\n minuteCallsUsed,\n minuteCallsLimit: MINUTE_LIMIT,\n minuteCallsRemaining: Math.max(0, MINUTE_LIMIT - minuteCallsUsed),\n topCommands,\n };\n}\n","import { resolve, normalize } from \"node:path\";\nimport { GpcError } from \"../errors.js\";\n\n/**\n * Normalize and resolve a user-supplied path.\n * Prevents path traversal by normalizing `.` and `..` components.\n */\nexport function safePath(userPath: string): string {\n return resolve(normalize(userPath));\n}\n\n/**\n * Validate that a resolved path is within an expected base directory.\n * Returns the resolved path or throws if it escapes the base.\n */\nexport function safePathWithin(userPath: string, baseDir: string): string {\n const resolved = safePath(userPath);\n const base = safePath(baseDir);\n\n if (!resolved.startsWith(base + \"/\") && resolved !== base) {\n throw new GpcError(\n `Path \"${userPath}\" resolves outside the expected directory \"${baseDir}\"`,\n \"PATH_TRAVERSAL\",\n 2,\n \"The path must stay within the target directory. Remove any ../ segments or use an absolute path within the expected directory.\",\n );\n }\n\n return resolved;\n}\n","// Named exports only. No default export.\n\nimport { mkdir, writeFile, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport interface InitOptions {\n dir: string;\n app?: string;\n ci?: \"github\" | \"gitlab\";\n skipExisting?: boolean;\n}\n\nexport interface InitResult {\n created: string[];\n skipped: string[];\n}\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function safeWrite(\n filePath: string,\n content: string,\n created: string[],\n skipped: string[],\n skipExisting: boolean,\n): Promise<void> {\n if (await exists(filePath)) {\n if (skipExisting) {\n skipped.push(filePath);\n return;\n }\n }\n const dir = filePath.substring(0, filePath.lastIndexOf(\"/\"));\n await mkdir(dir, { recursive: true });\n await writeFile(filePath, content, \"utf-8\");\n created.push(filePath);\n}\n\nexport async function initProject(options: InitOptions): Promise<InitResult> {\n const { dir, app, ci } = options;\n const skipExisting = options.skipExisting !== false;\n const created: string[] = [];\n const skipped: string[] = [];\n const pkg = app || \"com.example.app\";\n\n // .gpcrc.json\n const gpcrc = JSON.stringify(\n {\n app: pkg,\n output: \"table\",\n },\n null,\n 2,\n );\n await safeWrite(join(dir, \".gpcrc.json\"), gpcrc + \"\\n\", created, skipped, skipExisting);\n\n // .preflightrc.json\n const preflightrc = JSON.stringify(\n {\n failOn: \"error\",\n targetSdkMinimum: 35,\n maxDownloadSizeMb: 150,\n allowedPermissions: [],\n disabledRules: [],\n severityOverrides: {},\n },\n null,\n 2,\n );\n await safeWrite(\n join(dir, \".preflightrc.json\"),\n preflightrc + \"\\n\",\n created,\n skipped,\n skipExisting,\n );\n\n // metadata/android/en-US/ listing files\n const metaDir = join(dir, \"metadata\", \"android\", \"en-US\");\n await safeWrite(join(metaDir, \"title.txt\"), \"\", created, skipped, skipExisting);\n await safeWrite(join(metaDir, \"short_description.txt\"), \"\", created, skipped, skipExisting);\n await safeWrite(join(metaDir, \"full_description.txt\"), \"\", created, skipped, skipExisting);\n await safeWrite(join(metaDir, \"video.txt\"), \"\", created, skipped, skipExisting);\n\n // metadata/android/en-US/images/phoneScreenshots/\n const ssDir = join(metaDir, \"images\", \"phoneScreenshots\");\n await mkdir(ssDir, { recursive: true });\n await safeWrite(join(ssDir, \".gitkeep\"), \"\", created, skipped, skipExisting);\n\n // CI templates\n if (ci === \"github\") {\n const workflow = githubActionsTemplate(pkg);\n const workflowDir = join(dir, \".github\", \"workflows\");\n await safeWrite(join(workflowDir, \"gpc-release.yml\"), workflow, created, skipped, skipExisting);\n } else if (ci === \"gitlab\") {\n const pipeline = gitlabCiTemplate(pkg);\n await safeWrite(join(dir, \".gitlab-ci-gpc.yml\"), pipeline, created, skipped, skipExisting);\n }\n\n return { created, skipped };\n}\n\nfunction githubActionsTemplate(pkg: string): string {\n return `name: GPC Release\non:\n push:\n tags: ['v*']\n\njobs:\n release:\n runs-on: ubuntu-latest\n env:\n GPC_SERVICE_ACCOUNT: \\${{ secrets.GPC_SERVICE_ACCOUNT }}\n GPC_APP: ${pkg}\n steps:\n - uses: actions/checkout@v4\n\n - uses: actions/setup-node@v4\n with:\n node-version: 20\n\n - name: Build\n run: ./gradlew bundleRelease\n\n - name: Install GPC\n run: npm install -g @gpc-cli/cli\n\n - name: Preflight compliance check\n run: gpc preflight app/build/outputs/bundle/release/app-release.aab --fail-on error\n\n - name: Upload to internal track\n run: |\n gpc releases upload app/build/outputs/bundle/release/app-release.aab \\\\\n --track internal \\\\\n --json\n`;\n}\n\nfunction gitlabCiTemplate(pkg: string): string {\n return `# GPC Release Pipeline\n# Add GPC_SERVICE_ACCOUNT as a CI/CD variable (masked, protected)\n\nstages:\n - build\n - preflight\n - release\n\nvariables:\n GPC_APP: ${pkg}\n\nbuild:\n stage: build\n image: gradle:jdk17\n script:\n - ./gradlew bundleRelease\n artifacts:\n paths:\n - app/build/outputs/bundle/release/app-release.aab\n\npreflight:\n stage: preflight\n image: node:20\n script:\n - npm install -g @gpc-cli/cli\n - gpc preflight app/build/outputs/bundle/release/app-release.aab --fail-on error --json\n\nrelease:\n stage: release\n image: node:20\n script:\n - npm install -g @gpc-cli/cli\n - gpc releases upload app/build/outputs/bundle/release/app-release.aab --track internal\n only:\n - tags\n`;\n}\n","// Named exports only. No default export.\n\nexport type FindingSeverity = \"critical\" | \"error\" | \"warning\" | \"info\";\n\n/** Severity ordering for threshold comparisons. */\nexport const SEVERITY_ORDER: Record<FindingSeverity, number> = {\n info: 0,\n warning: 1,\n error: 2,\n critical: 3,\n};\n\nexport interface PreflightFinding {\n /** Scanner name, e.g. \"manifest\", \"permissions\" */\n scanner: string;\n /** Machine-readable rule ID, e.g. \"targetSdk-below-minimum\" */\n ruleId: string;\n severity: FindingSeverity;\n title: string;\n message: string;\n suggestion?: string;\n /** Link to the relevant Google Play policy page */\n policyUrl?: string;\n}\n\nexport interface PreflightContext {\n aabPath?: string;\n manifest?: ParsedManifest;\n zipEntries?: ZipEntryInfo[];\n metadataDir?: string;\n sourceDir?: string;\n config: PreflightConfig;\n}\n\nexport interface PreflightResult {\n scanners: string[];\n findings: PreflightFinding[];\n summary: Record<FindingSeverity, number>;\n passed: boolean;\n durationMs: number;\n}\n\nexport interface PreflightScanner {\n name: string;\n description: string;\n requires: (\"manifest\" | \"zipEntries\" | \"metadataDir\" | \"sourceDir\")[];\n scan(ctx: PreflightContext): Promise<PreflightFinding[]>;\n}\n\nexport interface PreflightConfig {\n failOn: FindingSeverity;\n targetSdkMinimum: number;\n maxDownloadSizeMb: number;\n allowedPermissions: string[];\n disabledRules: string[];\n severityOverrides: Record<string, FindingSeverity>;\n}\n\nexport interface PreflightOptions {\n aabPath?: string;\n metadataDir?: string;\n sourceDir?: string;\n scanners?: string[];\n failOn?: FindingSeverity;\n configPath?: string;\n}\n\nexport interface ParsedManifest {\n packageName: string;\n versionCode: number;\n versionName: string;\n minSdk: number;\n targetSdk: number;\n debuggable: boolean;\n testOnly: boolean;\n usesCleartextTraffic: boolean;\n extractNativeLibs: boolean;\n permissions: string[];\n features: ManifestFeature[];\n activities: ManifestComponent[];\n services: ManifestComponent[];\n receivers: ManifestComponent[];\n providers: ManifestComponent[];\n /** Set when the manifest could not be fully parsed — manifest-dependent scanners should skip. */\n _parseError?: string;\n}\n\nexport interface ManifestFeature {\n name: string;\n required: boolean;\n}\n\nexport interface ManifestComponent {\n name: string;\n exported?: boolean;\n foregroundServiceType?: string;\n hasIntentFilter: boolean;\n}\n\nexport interface ZipEntryInfo {\n path: string;\n compressedSize: number;\n uncompressedSize: number;\n}\n\nexport const DEFAULT_PREFLIGHT_CONFIG: PreflightConfig = {\n failOn: \"error\",\n targetSdkMinimum: 35,\n maxDownloadSizeMb: 150,\n allowedPermissions: [],\n disabledRules: [],\n severityOverrides: {},\n};\n","// Named exports only. No default export.\n\nimport { readFile } from \"node:fs/promises\";\nimport type { PreflightConfig, FindingSeverity } from \"./types.js\";\nimport { DEFAULT_PREFLIGHT_CONFIG } from \"./types.js\";\n\nconst VALID_SEVERITIES = new Set([\"critical\", \"error\", \"warning\", \"info\"]);\n\nexport async function loadPreflightConfig(configPath?: string): Promise<PreflightConfig> {\n const path = configPath || \".preflightrc.json\";\n\n let raw: string;\n try {\n raw = await readFile(path, \"utf-8\");\n } catch {\n return { ...DEFAULT_PREFLIGHT_CONFIG };\n }\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n throw new Error(`Invalid JSON in ${path}. Check the file for syntax errors.`);\n }\n\n const config: PreflightConfig = { ...DEFAULT_PREFLIGHT_CONFIG };\n\n if (typeof parsed[\"failOn\"] === \"string\" && VALID_SEVERITIES.has(parsed[\"failOn\"])) {\n config.failOn = parsed[\"failOn\"] as FindingSeverity;\n }\n\n if (typeof parsed[\"targetSdkMinimum\"] === \"number\" && parsed[\"targetSdkMinimum\"] > 0) {\n config.targetSdkMinimum = parsed[\"targetSdkMinimum\"];\n }\n\n if (typeof parsed[\"maxDownloadSizeMb\"] === \"number\" && parsed[\"maxDownloadSizeMb\"] > 0) {\n config.maxDownloadSizeMb = parsed[\"maxDownloadSizeMb\"];\n }\n\n if (Array.isArray(parsed[\"allowedPermissions\"])) {\n config.allowedPermissions = (parsed[\"allowedPermissions\"] as unknown[]).filter(\n (v): v is string => typeof v === \"string\",\n );\n }\n\n if (Array.isArray(parsed[\"disabledRules\"])) {\n config.disabledRules = (parsed[\"disabledRules\"] as unknown[]).filter(\n (v): v is string => typeof v === \"string\",\n );\n }\n\n if (typeof parsed[\"severityOverrides\"] === \"object\" && parsed[\"severityOverrides\"] !== null) {\n const overrides: Record<string, FindingSeverity> = {};\n for (const [key, val] of Object.entries(\n parsed[\"severityOverrides\"] as Record<string, unknown>,\n )) {\n if (typeof val === \"string\" && VALID_SEVERITIES.has(val)) {\n overrides[key] = val as FindingSeverity;\n }\n }\n config.severityOverrides = overrides;\n }\n\n return config;\n}\n","// Named exports only. No default export.\n\nimport { open as yauzlOpen, type Entry, type ZipFile } from \"yauzl\";\nimport type { ParsedManifest, ZipEntryInfo } from \"./types.js\";\nimport { decodeManifest } from \"./manifest-parser.js\";\n\nconst AAB_MANIFEST_PATH = \"base/manifest/AndroidManifest.xml\";\nconst APK_MANIFEST_PATH = \"AndroidManifest.xml\";\n\ninterface AabContents {\n manifest: ParsedManifest;\n entries: ZipEntryInfo[];\n}\n\nfunction detectManifestPath(filePath: string): string {\n return filePath.toLowerCase().endsWith(\".apk\") ? APK_MANIFEST_PATH : AAB_MANIFEST_PATH;\n}\n\n/**\n * Open an AAB or APK file, extract the manifest and ZIP entry list.\n * Uses yauzl for streaming — does not load the entire file into memory.\n */\nexport async function readAab(aabPath: string): Promise<AabContents> {\n const manifestPath = detectManifestPath(aabPath);\n const { zipfile, entries, manifestBuf } = await openAndScan(aabPath, manifestPath);\n zipfile.close();\n\n if (!manifestBuf) {\n const fileType = aabPath.toLowerCase().endsWith(\".apk\") ? \"APK\" : \"AAB\";\n throw new Error(\n `${fileType} is missing ${manifestPath}. This does not appear to be a valid Android ${fileType === \"APK\" ? \"application package\" : \"App Bundle\"}.`,\n );\n }\n\n let manifest: ParsedManifest;\n try {\n manifest = decodeManifest(manifestBuf);\n } catch (err) {\n // Some AABs have manifests that protobufjs cannot fully parse\n // (e.g., larger bundles with complex resource tables, ESM/CJS interop issues).\n // Fall back to a minimal manifest so non-manifest scanners can still run.\n const errMsg = err instanceof Error ? err.message : String(err);\n manifest = createFallbackManifest();\n manifest._parseError = `Manifest could not be fully parsed: ${errMsg}. Manifest-dependent checks will be skipped.`;\n }\n\n return { manifest, entries };\n}\n\nfunction createFallbackManifest(): ParsedManifest {\n return {\n packageName: \"\",\n versionCode: 0,\n versionName: \"\",\n minSdk: 0,\n targetSdk: 0,\n debuggable: false,\n testOnly: false,\n usesCleartextTraffic: false,\n extractNativeLibs: true,\n permissions: [],\n features: [],\n activities: [],\n services: [],\n receivers: [],\n providers: [],\n };\n}\n\n/**\n * Open ZIP, iterate entries, collect entry list and manifest buffer.\n * yauzl's lazyEntries mode ensures we control iteration — the \"end\" event\n * only fires after the last readEntry() call with no more entries.\n */\nfunction openAndScan(\n aabPath: string,\n manifestPath: string = AAB_MANIFEST_PATH,\n): Promise<{ zipfile: ZipFile; entries: ZipEntryInfo[]; manifestBuf: Buffer | null }> {\n return new Promise((resolve, reject) => {\n yauzlOpen(aabPath, { lazyEntries: true, autoClose: false }, (err, zipfile) => {\n if (err || !zipfile) {\n reject(err ?? new Error(\"Failed to open AAB file\"));\n return;\n }\n\n const entries: ZipEntryInfo[] = [];\n let manifestBuf: Buffer | null = null;\n let rejected = false;\n\n function fail(error: Error): void {\n if (!rejected) {\n rejected = true;\n zipfile.close();\n reject(error);\n }\n }\n\n zipfile.on(\"error\", fail);\n\n zipfile.on(\"entry\", (entry: Entry) => {\n if (rejected) return;\n const path = entry.fileName;\n\n // Collect entry metadata (skip directories)\n if (!path.endsWith(\"/\")) {\n entries.push({\n path,\n compressedSize: entry.compressedSize,\n uncompressedSize: entry.uncompressedSize,\n });\n }\n\n // Extract manifest content\n if (path === manifestPath) {\n zipfile.openReadStream(entry, (streamErr, stream) => {\n if (streamErr || !stream) {\n fail(streamErr ?? new Error(\"Failed to read manifest entry\"));\n return;\n }\n\n const chunks: Buffer[] = [];\n stream.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n stream.on(\"error\", (e: Error) => fail(e));\n stream.on(\"end\", () => {\n manifestBuf = Buffer.concat(chunks);\n // Continue to next entry after reading the manifest stream\n zipfile.readEntry();\n });\n });\n } else {\n zipfile.readEntry();\n }\n });\n\n zipfile.on(\"end\", () => {\n if (!rejected) {\n resolve({ zipfile, entries, manifestBuf });\n }\n });\n\n zipfile.readEntry();\n });\n });\n}\n","// Named exports only. No default export.\n\nimport protobuf from \"protobufjs\";\nimport type { ParsedManifest, ManifestComponent, ManifestFeature } from \"./types.js\";\n\n/**\n * Android resource IDs for common manifest attributes.\n * These map protobuf resource_id fields to human-readable names.\n */\nconst RESOURCE_IDS: Record<number, string> = {\n 0x01010000: \"theme\",\n 0x01010001: \"label\",\n 0x01010002: \"icon\",\n 0x01010003: \"name\",\n 0x0101000f: \"versionCode\",\n 0x01010010: \"versionName\",\n 0x0101020c: \"minSdkVersion\",\n 0x01010270: \"targetSdkVersion\",\n 0x0101001e: \"debuggable\",\n 0x01010022: \"permission\",\n 0x0101002b: \"exported\",\n 0x01010272: \"testOnly\",\n 0x010103f0: \"usesCleartextTraffic\",\n 0x010104ea: \"extractNativeLibs\",\n 0x010104d1: \"foregroundServiceType\",\n 0x0101028a: \"required\",\n 0x01010281: \"allowBackup\",\n};\n\n/**\n * Build the AAPT2 XmlNode protobuf schema programmatically.\n * This matches the structure in frameworks/base/tools/aapt2/Resources.proto.\n */\nfunction buildXmlSchema(): protobuf.Root {\n const root = new protobuf.Root();\n const ns = root.define(\"aapt.pb\");\n\n // Source message (line/column info — we skip reading this)\n const Source = new protobuf.Type(\"Source\")\n .add(new protobuf.Field(\"pathIdx\", 1, \"uint32\"))\n .add(new protobuf.Field(\"position\", 2, \"Position\"));\n const Position = new protobuf.Type(\"Position\")\n .add(new protobuf.Field(\"lineNumber\", 1, \"uint32\"))\n .add(new protobuf.Field(\"columnNumber\", 2, \"uint32\"));\n\n // Primitive item — used for compiled attribute values\n const Primitive = new protobuf.Type(\"Primitive\").add(\n new protobuf.OneOf(\"oneofValue\")\n .add(new protobuf.Field(\"intDecimalValue\", 6, \"int32\"))\n .add(new protobuf.Field(\"intHexadecimalValue\", 7, \"uint32\"))\n .add(new protobuf.Field(\"booleanValue\", 8, \"bool\"))\n .add(new protobuf.Field(\"floatValue\", 11, \"float\")),\n );\n\n // Reference — points to another resource\n const Reference = new protobuf.Type(\"Reference\")\n .add(new protobuf.Field(\"id\", 1, \"uint32\"))\n .add(new protobuf.Field(\"name\", 2, \"string\"));\n\n // Item — compiled value of an attribute\n const Item = new protobuf.Type(\"Item\").add(\n new protobuf.OneOf(\"value\")\n .add(new protobuf.Field(\"ref\", 1, \"Reference\"))\n .add(new protobuf.Field(\"str\", 2, \"String\"))\n .add(new protobuf.Field(\"prim\", 4, \"Primitive\")),\n );\n\n const StringMsg = new protobuf.Type(\"String\").add(new protobuf.Field(\"value\", 1, \"string\"));\n\n // XmlAttribute\n const XmlAttribute = new protobuf.Type(\"XmlAttribute\")\n .add(new protobuf.Field(\"namespaceUri\", 1, \"string\"))\n .add(new protobuf.Field(\"name\", 2, \"string\"))\n .add(new protobuf.Field(\"value\", 3, \"string\"))\n .add(new protobuf.Field(\"source\", 4, \"Source\"))\n .add(new protobuf.Field(\"resourceId\", 5, \"uint32\"))\n .add(new protobuf.Field(\"compiledItem\", 6, \"Item\"));\n\n // XmlNamespace\n const XmlNamespace = new protobuf.Type(\"XmlNamespace\")\n .add(new protobuf.Field(\"prefix\", 1, \"string\"))\n .add(new protobuf.Field(\"uri\", 2, \"string\"))\n .add(new protobuf.Field(\"source\", 3, \"Source\"));\n\n // XmlElement\n const XmlElement = new protobuf.Type(\"XmlElement\")\n .add(new protobuf.Field(\"namespaceDeclaration\", 1, \"XmlNamespace\", \"repeated\"))\n .add(new protobuf.Field(\"namespaceUri\", 2, \"string\"))\n .add(new protobuf.Field(\"name\", 3, \"string\"))\n .add(new protobuf.Field(\"attribute\", 4, \"XmlAttribute\", \"repeated\"))\n .add(new protobuf.Field(\"child\", 5, \"XmlNode\", \"repeated\"));\n\n // XmlNode\n const XmlNode = new protobuf.Type(\"XmlNode\")\n .add(\n new protobuf.OneOf(\"node\")\n .add(new protobuf.Field(\"element\", 1, \"XmlElement\"))\n .add(new protobuf.Field(\"text\", 2, \"string\")),\n )\n .add(new protobuf.Field(\"source\", 3, \"Source\"));\n\n ns.add(Position);\n ns.add(Source);\n ns.add(Primitive);\n ns.add(Reference);\n ns.add(StringMsg);\n ns.add(Item);\n ns.add(XmlAttribute);\n ns.add(XmlNamespace);\n ns.add(XmlElement);\n ns.add(XmlNode);\n\n return root;\n}\n\nlet cachedSchema: protobuf.Root | undefined;\n\nfunction getSchema(): protobuf.Root {\n if (!cachedSchema) cachedSchema = buildXmlSchema();\n return cachedSchema;\n}\n\ninterface XmlAttr {\n name: string;\n value: string;\n resourceId: number;\n compiledItem?: {\n prim?: { intDecimalValue?: number; intHexadecimalValue?: number; booleanValue?: boolean };\n str?: { value?: string };\n ref?: { id?: number; name?: string };\n };\n}\n\ninterface XmlElem {\n name: string;\n attribute: XmlAttr[];\n child: XmlNodeParsed[];\n}\n\ninterface XmlNodeParsed {\n element?: XmlElem;\n text?: string;\n}\n\n/** Decode a protobuf-encoded AndroidManifest.xml buffer into a parsed manifest. */\nexport function decodeManifest(buf: Buffer): ParsedManifest {\n const root = getSchema();\n const XmlNode = root.lookupType(\"aapt.pb.XmlNode\");\n const decoded = XmlNode.decode(buf) as unknown as XmlNodeParsed;\n\n if (!decoded.element || decoded.element.name !== \"manifest\") {\n throw new Error(\"Invalid AAB manifest: root element is not <manifest>\");\n }\n\n return extractManifestData(decoded.element);\n}\n\nfunction getAttrValue(attrs: XmlAttr[], resId: number): string | undefined {\n const attr = attrs.find((a) => a.resourceId === resId);\n if (!attr) return undefined;\n // The `value` string field is always populated and is the most reliable source.\n // compiledItem contains structured types but protobuf.js fills default values\n // for all oneof fields, making it unreliable for distinguishing which field is set.\n // Use compiledItem.str for string values (package names, etc.) and fall back to value.\n const ci = attr.compiledItem;\n if (ci?.str?.value !== undefined) return ci.str.value;\n if (ci?.ref?.name !== undefined) return ci.ref.name;\n // For primitives (int, bool), use the string `value` field which is always correct\n return attr.value || undefined;\n}\n\nfunction getAttrByName(attrs: XmlAttr[], name: string): string | undefined {\n const attr = attrs.find((a) => a.name === name || RESOURCE_IDS[a.resourceId] === name);\n if (!attr) return undefined;\n const ci = attr.compiledItem;\n if (ci?.str?.value !== undefined) return ci.str.value;\n if (ci?.ref?.name !== undefined) return ci.ref.name;\n return attr.value || undefined;\n}\n\nfunction getBoolAttr(attrs: XmlAttr[], resId: number, defaultVal: boolean): boolean {\n const val = getAttrValue(attrs, resId);\n if (val === undefined) return defaultVal;\n return val === \"true\" || val === \"1\";\n}\n\nfunction getIntAttr(attrs: XmlAttr[], resId: number, defaultVal: number): number {\n const val = getAttrValue(attrs, resId);\n if (val === undefined) return defaultVal;\n const n = parseInt(val, 10);\n return isNaN(n) ? defaultVal : n;\n}\n\nfunction getChildren(elem: XmlElem, tagName: string): XmlElem[] {\n return (elem.child || [])\n .filter((c): c is XmlNodeParsed & { element: XmlElem } => c.element?.name === tagName)\n .map((c) => c.element);\n}\n\nfunction extractManifestData(manifest: XmlElem): ParsedManifest {\n const attrs = manifest.attribute || [];\n\n const packageName = getAttrByName(attrs, \"package\") || \"\";\n const versionCode = getIntAttr(attrs, 0x0101000f, 0);\n const versionName = getAttrValue(attrs, 0x01010010) || \"\";\n\n // <uses-sdk> element\n const usesSdkElements = getChildren(manifest, \"uses-sdk\");\n const usesSdk = usesSdkElements[0];\n const minSdk = usesSdk ? getIntAttr(usesSdk.attribute || [], 0x0101020c, 1) : 1;\n const targetSdk = usesSdk ? getIntAttr(usesSdk.attribute || [], 0x01010270, minSdk) : minSdk;\n\n // <uses-permission> elements\n const permissions = getChildren(manifest, \"uses-permission\")\n .map((el) => getAttrValue(el.attribute || [], 0x01010003))\n .filter((p): p is string => p !== undefined);\n\n // <uses-feature> elements\n const features: ManifestFeature[] = getChildren(manifest, \"uses-feature\").map((el) => ({\n name: getAttrValue(el.attribute || [], 0x01010003) || \"\",\n required: getBoolAttr(el.attribute || [], 0x0101028a, true),\n }));\n\n // <application> element\n const appElements = getChildren(manifest, \"application\");\n const app = appElements[0];\n\n const debuggable = app ? getBoolAttr(app.attribute || [], 0x0101001e, false) : false;\n const testOnly = getBoolAttr(attrs, 0x01010272, false);\n const usesCleartextTraffic = app ? getBoolAttr(app.attribute || [], 0x010103f0, true) : true;\n const extractNativeLibs = app ? getBoolAttr(app.attribute || [], 0x010104ea, true) : true;\n\n const activities = app ? extractComponents(app, \"activity\") : [];\n const services = app ? extractComponents(app, \"service\") : [];\n const receivers = app ? extractComponents(app, \"receiver\") : [];\n const providers = app ? extractComponents(app, \"provider\") : [];\n\n return {\n packageName,\n versionCode,\n versionName,\n minSdk,\n targetSdk,\n debuggable,\n testOnly,\n usesCleartextTraffic,\n extractNativeLibs,\n permissions,\n features,\n activities,\n services,\n receivers,\n providers,\n };\n}\n\nfunction extractComponents(appElement: XmlElem, tagName: string): ManifestComponent[] {\n return getChildren(appElement, tagName).map((el) => {\n const compAttrs = el.attribute || [];\n const exportedVal = getAttrValue(compAttrs, 0x0101002b);\n const hasIntentFilter = getChildren(el, \"intent-filter\").length > 0;\n\n return {\n name: getAttrValue(compAttrs, 0x01010003) || \"\",\n exported:\n exportedVal === undefined ? undefined : exportedVal === \"true\" || exportedVal === \"1\",\n foregroundServiceType:\n tagName === \"service\" ? getAttrValue(compAttrs, 0x010104d1) : undefined,\n hasIntentFilter,\n };\n });\n}\n","// Named exports only. No default export.\n\nimport type { PreflightScanner, PreflightContext, PreflightFinding } from \"../types.js\";\n\nexport const manifestScanner: PreflightScanner = {\n name: \"manifest\",\n description: \"Checks AndroidManifest.xml for target SDK, debug flags, and component declarations\",\n requires: [\"manifest\"],\n\n async scan(ctx: PreflightContext): Promise<PreflightFinding[]> {\n const manifest = ctx.manifest!;\n const findings: PreflightFinding[] = [];\n const minTargetSdk = ctx.config.targetSdkMinimum;\n\n // targetSdkVersion check\n if (manifest.targetSdk < minTargetSdk) {\n findings.push({\n scanner: \"manifest\",\n ruleId: \"targetSdk-below-minimum\",\n severity: \"critical\",\n title: `targetSdkVersion ${manifest.targetSdk} is below the required ${minTargetSdk}`,\n message: `Google Play requires targetSdkVersion >= ${minTargetSdk} for new apps and updates. Your app targets API ${manifest.targetSdk}.`,\n suggestion: `Update targetSdkVersion to ${minTargetSdk} or higher in your build.gradle file.`,\n policyUrl: \"https://developer.android.com/google/play/requirements/target-sdk\",\n });\n }\n\n // debuggable check\n if (manifest.debuggable) {\n findings.push({\n scanner: \"manifest\",\n ruleId: \"debuggable-true\",\n severity: \"critical\",\n title: \"App is marked as debuggable\",\n message:\n 'android:debuggable=\"true\" is set in the manifest. Google Play rejects debuggable release builds.',\n suggestion:\n \"Remove android:debuggable from your manifest or set it to false. Release builds should never be debuggable.\",\n });\n }\n\n // testOnly check\n if (manifest.testOnly) {\n findings.push({\n scanner: \"manifest\",\n ruleId: \"testOnly-true\",\n severity: \"critical\",\n title: \"App is marked as testOnly\",\n message:\n 'android:testOnly=\"true\" is set in the manifest. Google Play rejects testOnly builds.',\n suggestion:\n \"Remove android:testOnly from your manifest. This flag is only for development builds.\",\n });\n }\n\n // versionCode check\n if (manifest.versionCode <= 0) {\n findings.push({\n scanner: \"manifest\",\n ruleId: \"versionCode-invalid\",\n severity: \"error\",\n title: \"Invalid versionCode\",\n message: `versionCode is ${manifest.versionCode}. It must be a positive integer.`,\n suggestion: \"Set a valid versionCode in your build.gradle file.\",\n });\n }\n\n // cleartext traffic\n if (manifest.usesCleartextTraffic && manifest.targetSdk >= 28) {\n findings.push({\n scanner: \"manifest\",\n ruleId: \"cleartext-traffic\",\n severity: \"warning\",\n title: \"Cleartext HTTP traffic is allowed\",\n message:\n 'android:usesCleartextTraffic=\"true\" allows unencrypted HTTP connections. This is a security risk.',\n suggestion:\n 'Set android:usesCleartextTraffic=\"false\" and use HTTPS. If specific domains need HTTP, use a network security config.',\n policyUrl: \"https://developer.android.com/privacy-and-security/security-config\",\n });\n }\n\n // missing android:exported on components with intent filters (required API 31+)\n if (manifest.targetSdk >= 31) {\n const allComponents = [\n ...manifest.activities,\n ...manifest.services,\n ...manifest.receivers,\n ...manifest.providers,\n ];\n\n for (const comp of allComponents) {\n if (comp.hasIntentFilter && comp.exported === undefined) {\n findings.push({\n scanner: \"manifest\",\n ruleId: \"missing-exported\",\n severity: \"error\",\n title: `Missing android:exported on ${comp.name}`,\n message: `Component \"${comp.name}\" has an intent-filter but no android:exported attribute. This is required for apps targeting API 31+.`,\n suggestion: `Add android:exported=\"true\" or android:exported=\"false\" to the <activity>, <service>, <receiver>, or <provider> declaration for \"${comp.name}\".`,\n policyUrl:\n \"https://developer.android.com/about/versions/12/behavior-changes-12#exported\",\n });\n }\n }\n }\n\n // foreground service type required (API 34+)\n if (manifest.targetSdk >= 34) {\n const hasFgsPerm = manifest.permissions.includes(\"android.permission.FOREGROUND_SERVICE\");\n\n if (hasFgsPerm) {\n for (const service of manifest.services) {\n if (!service.foregroundServiceType) {\n findings.push({\n scanner: \"manifest\",\n ruleId: \"foreground-service-type-missing\",\n severity: \"error\",\n title: `Missing foregroundServiceType on ${service.name}`,\n message: `Service \"${service.name}\" does not declare android:foregroundServiceType. This is required for apps targeting API 34+.`,\n suggestion: `Add android:foregroundServiceType to the <service> declaration. Valid types: camera, connectedDevice, dataSync, health, location, mediaPlayback, mediaProcessing, mediaProjection, microphone, phoneCall, remoteMessaging, shortService, specialUse, systemExempted.`,\n policyUrl:\n \"https://developer.android.com/about/versions/14/changes/fgs-types-required\",\n });\n }\n }\n }\n }\n\n // minSdkVersion advisory\n if (manifest.minSdk < 21) {\n findings.push({\n scanner: \"manifest\",\n ruleId: \"minSdk-below-21\",\n severity: \"info\",\n title: `minSdkVersion ${manifest.minSdk} is very low`,\n message: `minSdkVersion ${manifest.minSdk} means your app supports very old devices (pre-Lollipop). This limits split APK support and modern features.`,\n suggestion:\n \"Consider raising minSdkVersion to 21 or higher to take advantage of modern Android features and better app size optimization.\",\n });\n }\n\n return findings;\n },\n};\n","// Named exports only. No default export.\n\nimport type {\n PreflightScanner,\n PreflightContext,\n PreflightFinding,\n FindingSeverity,\n} from \"../types.js\";\n\ninterface RestrictedPermission {\n permission: string;\n severity: FindingSeverity;\n title: string;\n message: string;\n suggestion: string;\n policyUrl: string;\n}\n\nconst RESTRICTED_PERMISSIONS: RestrictedPermission[] = [\n // SMS permissions — only for default SMS handler\n {\n permission: \"android.permission.READ_SMS\",\n severity: \"critical\",\n title: \"READ_SMS requires declaration form\",\n message:\n \"READ_SMS is restricted to default SMS/phone/assistant handler apps. Google Play requires a Permissions Declaration Form and may reject apps using this permission without approval.\",\n suggestion:\n \"Remove READ_SMS unless your app is a default SMS handler. Use the SMS Retriever API or one-tap SMS consent for OTP verification.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10208820\",\n },\n {\n permission: \"android.permission.SEND_SMS\",\n severity: \"critical\",\n title: \"SEND_SMS requires declaration form\",\n message: \"SEND_SMS is restricted to default SMS handler apps.\",\n suggestion: \"Remove SEND_SMS unless your app is a default SMS handler.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10208820\",\n },\n {\n permission: \"android.permission.RECEIVE_SMS\",\n severity: \"critical\",\n title: \"RECEIVE_SMS requires declaration form\",\n message: \"RECEIVE_SMS is restricted to default SMS handler apps.\",\n suggestion: \"Remove RECEIVE_SMS. Use the SMS Retriever API for OTP verification instead.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10208820\",\n },\n {\n permission: \"android.permission.RECEIVE_MMS\",\n severity: \"critical\",\n title: \"RECEIVE_MMS requires declaration form\",\n message: \"RECEIVE_MMS is restricted to default SMS handler apps.\",\n suggestion: \"Remove RECEIVE_MMS unless your app is a default SMS handler.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10208820\",\n },\n {\n permission: \"android.permission.RECEIVE_WAP_PUSH\",\n severity: \"critical\",\n title: \"RECEIVE_WAP_PUSH requires declaration form\",\n message: \"RECEIVE_WAP_PUSH is restricted to default SMS handler apps.\",\n suggestion: \"Remove RECEIVE_WAP_PUSH unless your app is a default SMS handler.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10208820\",\n },\n // Call log permissions\n {\n permission: \"android.permission.READ_CALL_LOG\",\n severity: \"critical\",\n title: \"READ_CALL_LOG requires declaration form\",\n message: \"READ_CALL_LOG is restricted to default phone/assistant handler apps.\",\n suggestion: \"Remove READ_CALL_LOG unless your app is a default phone or assistant handler.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10208820\",\n },\n {\n permission: \"android.permission.WRITE_CALL_LOG\",\n severity: \"critical\",\n title: \"WRITE_CALL_LOG requires declaration form\",\n message: \"WRITE_CALL_LOG is restricted to default phone handler apps.\",\n suggestion: \"Remove WRITE_CALL_LOG unless your app is a default phone handler.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10208820\",\n },\n {\n permission: \"android.permission.PROCESS_OUTGOING_CALLS\",\n severity: \"critical\",\n title: \"PROCESS_OUTGOING_CALLS requires declaration form\",\n message: \"PROCESS_OUTGOING_CALLS is restricted to default phone handler apps.\",\n suggestion: \"Remove PROCESS_OUTGOING_CALLS unless your app is a default phone handler.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10208820\",\n },\n // Broad visibility\n {\n permission: \"android.permission.QUERY_ALL_PACKAGES\",\n severity: \"error\",\n title: \"QUERY_ALL_PACKAGES requires justification\",\n message:\n \"QUERY_ALL_PACKAGES grants broad package visibility. Google Play requires justification and may reject apps using this without approval.\",\n suggestion:\n \"Replace with targeted <queries> elements in your manifest to declare specific packages you need to interact with.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10158779\",\n },\n // All files access\n {\n permission: \"android.permission.MANAGE_EXTERNAL_STORAGE\",\n severity: \"error\",\n title: \"MANAGE_EXTERNAL_STORAGE (All Files Access) requires declaration form\",\n message:\n \"All Files Access is restricted to file managers, backup apps, antivirus, and document management apps.\",\n suggestion:\n \"Use scoped storage APIs or the Storage Access Framework (SAF) instead. Only use MANAGE_EXTERNAL_STORAGE if your app's core functionality requires broad file access.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10467955\",\n },\n // Background location\n {\n permission: \"android.permission.ACCESS_BACKGROUND_LOCATION\",\n severity: \"error\",\n title: \"ACCESS_BACKGROUND_LOCATION requires declaration and review\",\n message:\n \"Background location access requires a Permissions Declaration Form, privacy policy, and video demonstration. Extended review times apply.\",\n suggestion:\n \"Use foreground location with a foreground service instead. Only use background location if it is essential to your app's core functionality.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/9799150\",\n },\n // Photo/video permissions (May 2025 enforcement)\n {\n permission: \"android.permission.READ_MEDIA_IMAGES\",\n severity: \"error\",\n title: \"READ_MEDIA_IMAGES requires declaration or photo picker\",\n message:\n \"Photo/Video Permissions policy requires either an approved declaration form or use of the Android photo picker for one-time image access.\",\n suggestion:\n \"Use the Android photo picker (ACTION_PICK_IMAGES) for profile pictures and one-time use. Only declare READ_MEDIA_IMAGES if your app's core functionality requires broad gallery access.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/14115180\",\n },\n {\n permission: \"android.permission.READ_MEDIA_VIDEO\",\n severity: \"error\",\n title: \"READ_MEDIA_VIDEO requires declaration or photo picker\",\n message:\n \"Photo/Video Permissions policy requires either an approved declaration form or use of the Android photo picker for one-time video access.\",\n suggestion:\n \"Use the Android photo picker for one-time video selection. Only declare READ_MEDIA_VIDEO if your app's core functionality requires broad video access.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/14115180\",\n },\n // Install packages\n {\n permission: \"android.permission.REQUEST_INSTALL_PACKAGES\",\n severity: \"error\",\n title: \"REQUEST_INSTALL_PACKAGES requires justification\",\n message:\n \"REQUEST_INSTALL_PACKAGES is restricted to apps whose core purpose is installing other packages.\",\n suggestion:\n \"Remove REQUEST_INSTALL_PACKAGES unless your app is an app store, package manager, or OTA updater.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/12085295\",\n },\n // Exact alarm\n {\n permission: \"android.permission.USE_EXACT_ALARM\",\n severity: \"warning\",\n title: \"USE_EXACT_ALARM is restricted\",\n message:\n \"USE_EXACT_ALARM is only for alarm, timer, and calendar apps. Google Play may reject apps using this without justification.\",\n suggestion:\n \"Use SCHEDULE_EXACT_ALARM instead if possible, or remove exact alarm usage if your app does not need precise timing.\",\n policyUrl: \"https://developer.android.com/about/versions/14/changes/schedule-exact-alarms\",\n },\n // Full-screen intent\n {\n permission: \"android.permission.USE_FULL_SCREEN_INTENT\",\n severity: \"warning\",\n title: \"USE_FULL_SCREEN_INTENT requires declaration\",\n message:\n \"Full-screen intents are restricted to alarm and calling apps on Android 14+. A declaration form is required.\",\n suggestion: \"Remove USE_FULL_SCREEN_INTENT unless your app is an alarm clock or calling app.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/13392821\",\n },\n // Accessibility service\n {\n permission: \"android.permission.BIND_ACCESSIBILITY_SERVICE\",\n severity: \"error\",\n title: \"BIND_ACCESSIBILITY_SERVICE requires declaration and justification\",\n message:\n \"Accessibility services must support users with disabilities. A declaration form and detailed justification are required.\",\n suggestion:\n \"Only use BIND_ACCESSIBILITY_SERVICE if your app genuinely assists users with disabilities. Misuse leads to rejection.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10964491\",\n },\n // VPN\n {\n permission: \"android.permission.BIND_VPN_SERVICE\",\n severity: \"error\",\n title: \"BIND_VPN_SERVICE is restricted to VPN apps\",\n message:\n \"BIND_VPN_SERVICE is only for apps whose core functionality is providing VPN services.\",\n suggestion: \"Remove BIND_VPN_SERVICE unless your app is a VPN provider.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/9888170\",\n },\n];\n\n/** Map from permission string to restriction info for fast lookups. */\nconst RESTRICTED_MAP = new Map(RESTRICTED_PERMISSIONS.map((r) => [r.permission, r]));\n\nexport const permissionsScanner: PreflightScanner = {\n name: \"permissions\",\n description: \"Audits declared permissions against Google Play restricted permissions policies\",\n requires: [\"manifest\"],\n\n async scan(ctx: PreflightContext): Promise<PreflightFinding[]> {\n const manifest = ctx.manifest!;\n const findings: PreflightFinding[] = [];\n const allowed = new Set(ctx.config.allowedPermissions);\n\n for (const perm of manifest.permissions) {\n if (allowed.has(perm)) continue;\n\n const restriction = RESTRICTED_MAP.get(perm);\n if (restriction) {\n findings.push({\n scanner: \"permissions\",\n ruleId: `restricted-${perm.split(\".\").pop()?.toLowerCase() || perm}`,\n severity: restriction.severity,\n title: restriction.title,\n message: restriction.message,\n suggestion: restriction.suggestion,\n policyUrl: restriction.policyUrl,\n });\n }\n }\n\n // Data safety reminders for permissions that imply data collection\n const dataPermissions = [\n { perm: \"android.permission.ACCESS_FINE_LOCATION\", data: \"precise location\" },\n { perm: \"android.permission.ACCESS_COARSE_LOCATION\", data: \"approximate location\" },\n { perm: \"android.permission.READ_CONTACTS\", data: \"contacts\" },\n { perm: \"android.permission.CAMERA\", data: \"photos/videos via camera\" },\n { perm: \"android.permission.RECORD_AUDIO\", data: \"audio recordings\" },\n { perm: \"android.permission.READ_CALENDAR\", data: \"calendar events\" },\n { perm: \"android.permission.BODY_SENSORS\", data: \"health/fitness data\" },\n { perm: \"android.permission.ACTIVITY_RECOGNITION\", data: \"physical activity\" },\n ];\n\n const collectedData: string[] = [];\n for (const { perm, data } of dataPermissions) {\n if (manifest.permissions.includes(perm)) {\n collectedData.push(data);\n }\n }\n\n if (collectedData.length > 0) {\n findings.push({\n scanner: \"permissions\",\n ruleId: \"data-safety-reminder\",\n severity: \"info\",\n title: \"Data Safety declaration reminder\",\n message: `Your app declares permissions that imply collecting: ${collectedData.join(\", \")}. Ensure your Data Safety form in Play Console accurately reflects this data collection.`,\n suggestion:\n \"Review your Data Safety declaration at Play Console > Policy > App content > Data safety.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10787469\",\n });\n }\n\n return findings;\n },\n};\n","// Named exports only. No default export.\n\nimport type { PreflightScanner, PreflightContext, PreflightFinding } from \"../types.js\";\n\nconst KNOWN_ABIS = [\"arm64-v8a\", \"armeabi-v7a\", \"x86\", \"x86_64\"] as const;\n\n/** Regex to match native library paths in AAB or APK. */\nconst LIB_PATH_RE = /^(?:[^/]+\\/)?lib\\/([^/]+)\\/[^/]+\\.so$/;\n\nexport const nativeLibsScanner: PreflightScanner = {\n name: \"native-libs\",\n description: \"Checks native library architectures for 64-bit compliance\",\n requires: [\"zipEntries\"],\n\n async scan(ctx: PreflightContext): Promise<PreflightFinding[]> {\n const entries = ctx.zipEntries!;\n const findings: PreflightFinding[] = [];\n\n // Detect which ABIs are present\n const abisFound = new Set<string>();\n let totalNativeSize = 0;\n\n for (const entry of entries) {\n const match = LIB_PATH_RE.exec(entry.path);\n if (match) {\n abisFound.add(match[1]!);\n totalNativeSize += entry.uncompressedSize;\n }\n }\n\n // No native libraries — nothing to check\n if (abisFound.size === 0) {\n return findings;\n }\n\n // 64-bit requirement: if 32-bit ABIs exist, 64-bit counterparts must also exist\n const has32Arm = abisFound.has(\"armeabi-v7a\");\n const has64Arm = abisFound.has(\"arm64-v8a\");\n const has32x86 = abisFound.has(\"x86\");\n const has64x86 = abisFound.has(\"x86_64\");\n\n if (has32Arm && !has64Arm) {\n findings.push({\n scanner: \"native-libs\",\n ruleId: \"missing-arm64\",\n severity: \"critical\",\n title: \"Missing arm64-v8a native libraries\",\n message:\n \"App includes armeabi-v7a (32-bit ARM) native libraries but is missing arm64-v8a (64-bit ARM). Google Play requires 64-bit support for all apps with native code.\",\n suggestion:\n \"Build your native libraries for arm64-v8a. In build.gradle: ndk { abiFilters 'armeabi-v7a', 'arm64-v8a' }\",\n policyUrl: \"https://developer.android.com/google/play/requirements/64-bit\",\n });\n }\n\n if (has32x86 && !has64x86) {\n findings.push({\n scanner: \"native-libs\",\n ruleId: \"missing-x86_64\",\n severity: \"warning\",\n title: \"Missing x86_64 native libraries\",\n message:\n \"App includes x86 (32-bit) native libraries but is missing x86_64 (64-bit). While ARM is required, x86_64 is recommended for emulator and Chromebook support.\",\n suggestion:\n \"Add x86_64 to your ABI filters if you support x86: ndk { abiFilters 'x86', 'x86_64' }\",\n policyUrl: \"https://developer.android.com/google/play/requirements/64-bit\",\n });\n }\n\n // Report detected ABIs\n const detectedAbis = KNOWN_ABIS.filter((abi) => abisFound.has(abi));\n const unknownAbis = [...abisFound].filter(\n (abi) => !(KNOWN_ABIS as readonly string[]).includes(abi),\n );\n\n const abiList = [...detectedAbis, ...unknownAbis].join(\", \");\n const sizeMb = (totalNativeSize / (1024 * 1024)).toFixed(1);\n\n findings.push({\n scanner: \"native-libs\",\n ruleId: \"native-libs-summary\",\n severity: \"info\",\n title: `Native libraries: ${abiList}`,\n message: `Found native libraries for ${abisFound.size} architecture(s): ${abiList}. Total uncompressed size: ${sizeMb} MB.`,\n });\n\n // Warn on large native libraries\n if (totalNativeSize > 150 * 1024 * 1024) {\n findings.push({\n scanner: \"native-libs\",\n ruleId: \"native-libs-large\",\n severity: \"warning\",\n title: \"Large native libraries\",\n message: `Native libraries total ${sizeMb} MB (uncompressed). This significantly increases download size.`,\n suggestion:\n \"Consider using Android App Bundles to deliver only the required ABI per device. Review if all native libraries are necessary.\",\n });\n }\n\n return findings;\n },\n};\n","// Named exports only. No default export.\n\nimport { readdir, stat, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { PreflightScanner, PreflightContext, PreflightFinding } from \"../types.js\";\nimport { lintListing, DEFAULT_LIMITS } from \"../../utils/listing-text.js\";\n\nconst SAFE_LANG = /^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8})*$/;\n\nconst FILE_MAP: Record<string, string> = {\n \"title.txt\": \"title\",\n \"short_description.txt\": \"shortDescription\",\n \"full_description.txt\": \"fullDescription\",\n \"video.txt\": \"video\",\n};\n\nconst SCREENSHOT_DIRS = [\n \"phoneScreenshots\",\n \"sevenInchScreenshots\",\n \"tenInchScreenshots\",\n \"tvScreenshots\",\n \"wearScreenshots\",\n];\n\nconst MIN_PHONE_SCREENSHOTS = 2;\nconst RECOMMENDED_PHONE_SCREENSHOTS = 4;\n\nexport const metadataScanner: PreflightScanner = {\n name: \"metadata\",\n description:\n \"Checks store listing metadata for character limits, required fields, and screenshots\",\n requires: [\"metadataDir\"],\n\n async scan(ctx: PreflightContext): Promise<PreflightFinding[]> {\n const dir = ctx.metadataDir!;\n const findings: PreflightFinding[] = [];\n\n let entries: string[];\n try {\n entries = await readdir(dir);\n } catch {\n findings.push({\n scanner: \"metadata\",\n ruleId: \"metadata-dir-not-found\",\n severity: \"error\",\n title: \"Metadata directory not found\",\n message: `Cannot read metadata directory: ${dir}`,\n suggestion:\n \"Check the path to your metadata directory. Expected Fastlane format: <dir>/<lang>/title.txt, short_description.txt, etc.\",\n });\n return findings;\n }\n\n const locales = entries.filter((e) => SAFE_LANG.test(e));\n if (locales.length === 0) {\n findings.push({\n scanner: \"metadata\",\n ruleId: \"no-locales-found\",\n severity: \"error\",\n title: \"No locale directories found\",\n message: `No valid locale directories found in ${dir}. Expected subdirectories like en-US/, fr-FR/, etc.`,\n suggestion: \"Create locale directories with listing files: <dir>/en-US/title.txt\",\n });\n return findings;\n }\n\n for (const lang of locales) {\n const langDir = join(dir, lang);\n const langStat = await stat(langDir).catch(() => null);\n if (!langStat?.isDirectory()) continue;\n\n // Read listing fields\n const fields: Record<string, string> = {};\n for (const [fileName, field] of Object.entries(FILE_MAP)) {\n const filePath = join(langDir, fileName);\n try {\n const content = await readFile(filePath, \"utf-8\");\n fields[field] = content.trimEnd();\n } catch {\n // File doesn't exist — field is empty\n }\n }\n\n // Lint character limits\n const lintResult = lintListing(lang, fields, DEFAULT_LIMITS);\n for (const field of lintResult.fields) {\n if (field.status === \"over\") {\n findings.push({\n scanner: \"metadata\",\n ruleId: `listing-${field.field}-over-limit`,\n severity: \"error\",\n title: `${lang}: ${field.field} exceeds ${field.limit} character limit`,\n message: `${field.field} is ${field.chars} characters (limit: ${field.limit}). Google Play will reject this listing.`,\n suggestion: `Shorten ${field.field} to ${field.limit} characters or fewer.`,\n });\n } else if (field.status === \"warn\") {\n findings.push({\n scanner: \"metadata\",\n ruleId: `listing-${field.field}-near-limit`,\n severity: \"info\",\n title: `${lang}: ${field.field} is ${field.pct}% of limit`,\n message: `${field.field} is ${field.chars}/${field.limit} characters (${field.pct}%).`,\n });\n }\n }\n\n // Check for missing title\n if (!fields[\"title\"]?.trim()) {\n findings.push({\n scanner: \"metadata\",\n ruleId: \"listing-missing-title\",\n severity: \"error\",\n title: `${lang}: Missing title`,\n message: `No title.txt found or file is empty for locale ${lang}.`,\n suggestion: \"Create a title.txt file with your app name (max 30 characters).\",\n });\n }\n\n // Check screenshot count\n let totalScreenshots = 0;\n let phoneScreenshots = 0;\n\n for (const ssDir of SCREENSHOT_DIRS) {\n const ssPath = join(langDir, \"images\", ssDir);\n try {\n const ssEntries = await readdir(ssPath);\n const imageFiles = ssEntries.filter((f) => /\\.(png|jpe?g|webp)$/i.test(f));\n totalScreenshots += imageFiles.length;\n if (ssDir === \"phoneScreenshots\") {\n phoneScreenshots = imageFiles.length;\n }\n } catch {\n // Screenshot directory doesn't exist\n }\n }\n\n if (phoneScreenshots < MIN_PHONE_SCREENSHOTS && totalScreenshots === 0) {\n findings.push({\n scanner: \"metadata\",\n ruleId: \"listing-no-screenshots\",\n severity: \"warning\",\n title: `${lang}: No screenshots found`,\n message: `No screenshot images found for locale ${lang}. Google Play requires at least 2 phone screenshots.`,\n suggestion: `Add PNG or JPEG screenshots to ${lang}/images/phoneScreenshots/`,\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/9866151\",\n });\n } else if (phoneScreenshots < RECOMMENDED_PHONE_SCREENSHOTS && phoneScreenshots > 0) {\n findings.push({\n scanner: \"metadata\",\n ruleId: \"listing-few-screenshots\",\n severity: \"info\",\n title: `${lang}: Only ${phoneScreenshots} phone screenshot(s)`,\n message: `Found ${phoneScreenshots} phone screenshot(s). Google recommends at least ${RECOMMENDED_PHONE_SCREENSHOTS} for better store presence.`,\n });\n }\n }\n\n // Check for privacy policy URL\n const defaultLang = locales.includes(\"en-US\") ? \"en-US\" : locales[0]!;\n const privacyPath = join(dir, defaultLang, \"privacy_policy_url.txt\");\n try {\n const url = await readFile(privacyPath, \"utf-8\");\n if (!url.trim()) throw new Error(\"empty\");\n } catch {\n findings.push({\n scanner: \"metadata\",\n ruleId: \"listing-no-privacy-policy\",\n severity: \"warning\",\n title: \"No privacy policy URL\",\n message:\n \"No privacy_policy_url.txt found in metadata. A privacy policy is required for most apps on Google Play.\",\n suggestion: `Create ${defaultLang}/privacy_policy_url.txt with a link to your privacy policy.`,\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/9859455\",\n });\n }\n\n // Summary\n findings.push({\n scanner: \"metadata\",\n ruleId: \"metadata-summary\",\n severity: \"info\",\n title: `${locales.length} locale(s) found`,\n message: `Scanned metadata for: ${locales.join(\", \")}`,\n });\n\n return findings;\n },\n};\n","// Named exports only. No default export.\n\nimport { readFile } from \"node:fs/promises\";\nimport type {\n PreflightScanner,\n PreflightContext,\n PreflightFinding,\n FindingSeverity,\n} from \"../types.js\";\nimport { collectSourceFiles } from \"../scan-files.js\";\n\ninterface SecretPattern {\n ruleId: string;\n name: string;\n pattern: RegExp;\n severity: FindingSeverity;\n suggestion: string;\n}\n\nconst SECRET_PATTERNS: SecretPattern[] = [\n {\n ruleId: \"secret-aws-key\",\n name: \"AWS Access Key\",\n pattern: /AKIA[0-9A-Z]{16}/,\n severity: \"critical\",\n suggestion: \"Use environment variables or AWS Secrets Manager. Never hardcode AWS credentials.\",\n },\n {\n ruleId: \"secret-google-api-key\",\n name: \"Google API Key\",\n pattern: /AIza[0-9A-Za-z\\-_]{35}/,\n severity: \"critical\",\n suggestion:\n \"Move Google API keys to local.properties or environment variables. Restrict keys in Google Cloud Console.\",\n },\n {\n ruleId: \"secret-stripe-key\",\n name: \"Stripe Secret Key\",\n pattern: /sk_live_[0-9a-zA-Z]{24,}/,\n severity: \"critical\",\n suggestion:\n \"Never ship Stripe secret keys in client code. Use your backend server for Stripe API calls.\",\n },\n {\n ruleId: \"secret-stripe-restricted\",\n name: \"Stripe Restricted Key\",\n pattern: /rk_live_[0-9a-zA-Z]{24,}/,\n severity: \"critical\",\n suggestion: \"Stripe restricted keys should not be in client code. Use server-side integration.\",\n },\n {\n ruleId: \"secret-private-key\",\n name: \"Private Key\",\n pattern: /-----BEGIN\\s+(RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/,\n severity: \"critical\",\n suggestion:\n \"Remove private keys from source code. Store them in a secure key management system.\",\n },\n {\n ruleId: \"secret-firebase-key\",\n name: \"Firebase API Key in code\",\n pattern: /[\"']AIza[0-9A-Za-z\\-_]{35}[\"']/,\n severity: \"warning\",\n suggestion:\n \"Firebase API keys in client code are normal for google-services.json, but verify they are restricted in Google Cloud Console.\",\n },\n {\n ruleId: \"secret-generic-token\",\n name: \"Generic API Token\",\n pattern:\n /(?:api[_-]?key|api[_-]?secret|auth[_-]?token|access[_-]?token)\\s*[:=]\\s*[\"'][a-zA-Z0-9\\-_]{20,}[\"']/i,\n severity: \"warning\",\n suggestion:\n \"Avoid hardcoding tokens. Use BuildConfig fields, environment variables, or a secrets manager.\",\n },\n];\n\nconst SCAN_EXTENSIONS = new Set([\n \".ts\",\n \".js\",\n \".tsx\",\n \".jsx\",\n \".kt\",\n \".java\",\n \".xml\",\n \".json\",\n \".properties\",\n \".yaml\",\n \".yml\",\n \".gradle\",\n]);\n\nexport const secretsScanner: PreflightScanner = {\n name: \"secrets\",\n description: \"Scans source code for hardcoded credentials and API keys\",\n requires: [\"sourceDir\"],\n\n async scan(ctx: PreflightContext): Promise<PreflightFinding[]> {\n const dir = ctx.sourceDir!;\n const findings: PreflightFinding[] = [];\n const files = await collectSourceFiles(dir, SCAN_EXTENSIONS);\n\n for (const filePath of files) {\n let content: string;\n try {\n content = await readFile(filePath, \"utf-8\");\n } catch {\n continue;\n }\n\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n for (const pattern of SECRET_PATTERNS) {\n if (pattern.pattern.test(line)) {\n const relativePath = filePath.startsWith(dir)\n ? filePath.slice(dir.length + 1)\n : filePath;\n\n findings.push({\n scanner: \"secrets\",\n ruleId: pattern.ruleId,\n severity: pattern.severity,\n title: `${pattern.name} found in ${relativePath}:${i + 1}`,\n message: `Potential ${pattern.name} detected at ${relativePath} line ${i + 1}.`,\n suggestion: pattern.suggestion,\n });\n break; // Only report first match per line\n }\n }\n }\n }\n\n return findings;\n },\n};\n","// Named exports only. No default export.\n\nimport { readdir, stat } from \"node:fs/promises\";\nimport { join, extname } from \"node:path\";\n\nconst DEFAULT_SKIP_DIRS = new Set([\n \".git\",\n \"node_modules\",\n \"build\",\n \"dist\",\n \".gradle\",\n \"__pycache__\",\n \".idea\",\n \".vscode\",\n \"vendor\",\n]);\n\n/**\n * Recursively collect files matching the given extensions.\n * Skips common non-source directories (node_modules, build, .git, etc.).\n */\nexport async function collectSourceFiles(\n dir: string,\n extensions: Set<string>,\n skipDirs: Set<string> = DEFAULT_SKIP_DIRS,\n maxDepth: number = 10,\n): Promise<string[]> {\n if (maxDepth <= 0) return [];\n const files: string[] = [];\n\n let entries: string[];\n try {\n entries = await readdir(dir);\n } catch {\n return files;\n }\n\n for (const entry of entries) {\n if (skipDirs.has(entry)) continue;\n\n const fullPath = join(dir, entry);\n const s = await stat(fullPath).catch(() => null);\n if (!s) continue;\n\n if (s.isDirectory()) {\n const sub = await collectSourceFiles(fullPath, extensions, skipDirs, maxDepth - 1);\n files.push(...sub);\n } else if (s.isFile()) {\n const ext = extname(entry).toLowerCase();\n // Also match compound extensions like .gradle.kts\n if (extensions.has(ext) || entry.endsWith(\".gradle.kts\")) {\n files.push(fullPath);\n }\n }\n }\n\n return files;\n}\n","// Named exports only. No default export.\n\nimport { readFile } from \"node:fs/promises\";\nimport type { PreflightScanner, PreflightContext, PreflightFinding } from \"../types.js\";\nimport { collectSourceFiles } from \"../scan-files.js\";\n\ninterface BillingPattern {\n ruleId: string;\n name: string;\n pattern: RegExp;\n message: string;\n suggestion: string;\n}\n\nconst BILLING_PATTERNS: BillingPattern[] = [\n {\n ruleId: \"billing-stripe-sdk\",\n name: \"Stripe SDK\",\n pattern: /(?:com\\.stripe|@stripe\\/|stripe-android|StripeSdk)/,\n message:\n \"Stripe SDK detected. Google Play requires Play Billing for in-app purchases of digital goods.\",\n suggestion:\n \"If selling digital goods, use Google Play Billing Library. Stripe is only allowed for physical goods, services, or out-of-app purchases.\",\n },\n {\n ruleId: \"billing-braintree-sdk\",\n name: \"Braintree SDK\",\n pattern: /(?:com\\.braintreepayments|braintree-android)/,\n message:\n \"Braintree SDK detected. Google Play requires Play Billing for digital in-app purchases.\",\n suggestion:\n \"Use Google Play Billing Library for digital goods. Braintree is only allowed for physical goods and services.\",\n },\n {\n ruleId: \"billing-paypal-sdk\",\n name: \"PayPal SDK\",\n pattern: /(?:com\\.paypal|paypal-android)/,\n message: \"PayPal SDK detected. Google Play requires Play Billing for digital in-app purchases.\",\n suggestion:\n \"Use Google Play Billing Library for digital goods. PayPal is allowed for physical goods only.\",\n },\n {\n ruleId: \"billing-razorpay-sdk\",\n name: \"Razorpay SDK\",\n pattern: /(?:com\\.razorpay)/,\n message:\n \"Razorpay SDK detected. If used for digital goods, this may violate Google Play billing policy.\",\n suggestion:\n \"Ensure Razorpay is only used for physical goods/services. Digital goods require Play Billing.\",\n },\n {\n ruleId: \"billing-checkout-sdk\",\n name: \"Alternative checkout SDK\",\n pattern: /(?:com\\.adyen|com\\.checkout|com\\.square\\.sdk)/,\n message:\n \"Alternative payment SDK detected. Google Play requires Play Billing for digital goods.\",\n suggestion:\n \"Verify this payment SDK is only used for physical goods or services, not digital content.\",\n },\n];\n\nconst SCAN_EXTENSIONS = new Set([\n \".kt\",\n \".java\",\n \".xml\",\n \".gradle\",\n \".ts\",\n \".js\",\n \".tsx\",\n \".jsx\",\n \".json\",\n]);\n\nexport const billingScanner: PreflightScanner = {\n name: \"billing\",\n description: \"Detects non-Play billing SDKs that may violate Google Play billing policy\",\n requires: [\"sourceDir\"],\n\n async scan(ctx: PreflightContext): Promise<PreflightFinding[]> {\n const dir = ctx.sourceDir!;\n const findings: PreflightFinding[] = [];\n const detectedSdks = new Set<string>();\n const files = await collectSourceFiles(dir, SCAN_EXTENSIONS);\n\n for (const filePath of files) {\n let content: string;\n try {\n content = await readFile(filePath, \"utf-8\");\n } catch {\n continue;\n }\n\n for (const bp of BILLING_PATTERNS) {\n if (detectedSdks.has(bp.ruleId)) continue; // Only report each SDK once\n\n if (bp.pattern.test(content)) {\n const relativePath = filePath.startsWith(dir) ? filePath.slice(dir.length + 1) : filePath;\n\n detectedSdks.add(bp.ruleId);\n findings.push({\n scanner: \"billing\",\n ruleId: bp.ruleId,\n severity: \"warning\",\n title: `${bp.name} detected`,\n message: `${bp.message} Found in ${relativePath}.`,\n suggestion: bp.suggestion,\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10281818\",\n });\n }\n }\n }\n\n return findings;\n },\n};\n","// Named exports only. No default export.\n\nimport { readFile } from \"node:fs/promises\";\nimport type { PreflightScanner, PreflightContext, PreflightFinding } from \"../types.js\";\nimport { collectSourceFiles } from \"../scan-files.js\";\n\ninterface TrackingSdk {\n name: string;\n pattern: RegExp;\n}\n\nconst TRACKING_SDKS: TrackingSdk[] = [\n {\n name: \"Facebook SDK\",\n pattern: /(?:com\\.facebook\\.sdk|com\\.facebook\\.android|FacebookSdk\\.sdkInitialize)/i,\n },\n { name: \"Adjust SDK\", pattern: /(?:com\\.adjust\\.sdk|AdjustConfig|AdjustEvent)/i },\n {\n name: \"AppsFlyer SDK\",\n pattern: /(?:com\\.appsflyer|AppsFlyerLib|AppsFlyerConversionListener)/i,\n },\n { name: \"Amplitude SDK\", pattern: /(?:com\\.amplitude|AmplitudeClient|@amplitude\\/analytics)/i },\n { name: \"Mixpanel SDK\", pattern: /(?:com\\.mixpanel|MixpanelAPI|@mixpanel)/i },\n { name: \"Branch SDK\", pattern: /(?:io\\.branch\\.referral|Branch\\.getInstance)/i },\n { name: \"CleverTap SDK\", pattern: /(?:com\\.clevertap|CleverTapAPI)/i },\n { name: \"Singular SDK\", pattern: /(?:com\\.singular\\.sdk|SingularConfig)/i },\n];\n\nconst SCAN_EXTENSIONS = new Set([\n \".kt\",\n \".java\",\n \".xml\",\n \".gradle\",\n \".ts\",\n \".js\",\n \".tsx\",\n \".jsx\",\n \".json\",\n]);\n\nexport const privacyScanner: PreflightScanner = {\n name: \"privacy\",\n description: \"Detects tracking SDKs and data collection patterns for Data Safety compliance\",\n requires: [\"sourceDir\"],\n\n async scan(ctx: PreflightContext): Promise<PreflightFinding[]> {\n const dir = ctx.sourceDir!;\n const findings: PreflightFinding[] = [];\n const detectedSdks = new Set<string>();\n const files = await collectSourceFiles(dir, SCAN_EXTENSIONS);\n\n for (const filePath of files) {\n let content: string;\n try {\n content = await readFile(filePath, \"utf-8\");\n } catch {\n continue;\n }\n\n // Check for tracking SDKs\n for (const sdk of TRACKING_SDKS) {\n if (detectedSdks.has(sdk.name)) continue;\n\n if (sdk.pattern.test(content)) {\n detectedSdks.add(sdk.name);\n const relativePath = filePath.startsWith(dir) ? filePath.slice(dir.length + 1) : filePath;\n\n findings.push({\n scanner: \"privacy\",\n ruleId: `tracking-${sdk.name.toLowerCase().replace(/\\s+/g, \"-\")}`,\n severity: \"warning\",\n title: `${sdk.name} detected`,\n message: `${sdk.name} found in ${relativePath}. This SDK typically collects analytics or attribution data that must be declared in your Data Safety form.`,\n suggestion:\n \"Ensure your Data Safety declaration accurately lists all data types collected by this SDK.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10787469\",\n });\n }\n }\n\n // Check for ADVERTISING_ID\n if (\n content.includes(\"AD_ID\") ||\n content.includes(\"ADVERTISING_ID\") ||\n content.includes(\"AdvertisingIdClient\")\n ) {\n if (!detectedSdks.has(\"_ad_id\")) {\n detectedSdks.add(\"_ad_id\");\n findings.push({\n scanner: \"privacy\",\n ruleId: \"advertising-id-usage\",\n severity: \"warning\",\n title: \"Advertising ID usage detected\",\n message:\n \"Your app appears to access the Advertising ID. This must be declared in your Data Safety form under 'Device or other IDs'.\",\n suggestion:\n \"Declare Advertising ID collection in Play Console > Data safety. If your app targets children, Advertising ID usage is restricted.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/11043825\",\n });\n }\n }\n }\n\n // Cross-reference with manifest permissions if available\n if (ctx.manifest) {\n const dataPermissions: Array<{ perm: string; dataType: string }> = [\n { perm: \"android.permission.ACCESS_FINE_LOCATION\", dataType: \"precise location\" },\n { perm: \"android.permission.ACCESS_COARSE_LOCATION\", dataType: \"approximate location\" },\n { perm: \"android.permission.READ_CONTACTS\", dataType: \"contacts\" },\n { perm: \"android.permission.CAMERA\", dataType: \"photos/videos\" },\n { perm: \"android.permission.RECORD_AUDIO\", dataType: \"audio\" },\n { perm: \"android.permission.READ_CALENDAR\", dataType: \"calendar\" },\n { perm: \"android.permission.BODY_SENSORS\", dataType: \"health/fitness data\" },\n { perm: \"android.permission.READ_PHONE_STATE\", dataType: \"phone state/device ID\" },\n ];\n\n const collectedTypes: string[] = [];\n for (const { perm, dataType } of dataPermissions) {\n if (ctx.manifest.permissions.includes(perm)) {\n collectedTypes.push(dataType);\n }\n }\n\n if (collectedTypes.length > 0 && detectedSdks.size > 0) {\n findings.push({\n scanner: \"privacy\",\n ruleId: \"data-collection-cross-reference\",\n severity: \"info\",\n title: \"Data collection cross-reference\",\n message: `Your app requests permissions for: ${collectedTypes.join(\", \")}. Combined with ${detectedSdks.size} tracking SDK(s), ensure your Data Safety form declares all collected data types.`,\n suggestion:\n \"Review your Data Safety form at Play Console > Policy > App content > Data safety.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10787469\",\n });\n }\n }\n\n return findings;\n },\n};\n","// Named exports only. No default export.\n\nimport type { PreflightScanner, PreflightContext, PreflightFinding } from \"../types.js\";\n\n/** Heuristic policy checks based on manifest permissions and features. */\nexport const policyScanner: PreflightScanner = {\n name: \"policy\",\n description:\n \"Heuristic checks for Google Play policy compliance (families, financial, health, gambling)\",\n requires: [\"manifest\"],\n\n async scan(ctx: PreflightContext): Promise<PreflightFinding[]> {\n const manifest = ctx.manifest!;\n const findings: PreflightFinding[] = [];\n const perms = new Set(manifest.permissions);\n\n // Families / COPPA indicators\n if (manifest.targetSdk >= 28) {\n const childrenIndicators = [\n perms.has(\"android.permission.READ_CONTACTS\"),\n perms.has(\"android.permission.ACCESS_FINE_LOCATION\"),\n perms.has(\"android.permission.RECORD_AUDIO\"),\n ];\n const hasChildFeatures = manifest.features.some(\n (f) =>\n f.name.includes(\"kids\") || f.name.includes(\"children\") || f.name.includes(\"education\"),\n );\n\n if (hasChildFeatures && childrenIndicators.some(Boolean)) {\n findings.push({\n scanner: \"policy\",\n ruleId: \"policy-families-data-collection\",\n severity: \"warning\",\n title: \"Potential Families Policy concern\",\n message:\n \"App appears to target children (based on features) but requests sensitive permissions (location, contacts, or audio). Apps in the Families program have strict data collection limits.\",\n suggestion:\n \"Review the Families Policy requirements. Apps for children must minimize data collection and cannot use advertising ID.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/9893335\",\n });\n }\n }\n\n // Financial app indicators\n const financialPerms = [\n perms.has(\"android.permission.READ_SMS\"),\n perms.has(\"android.permission.RECEIVE_SMS\"),\n perms.has(\"android.permission.BIND_AUTOFILL_SERVICE\"),\n ];\n if (financialPerms.filter(Boolean).length >= 2) {\n findings.push({\n scanner: \"policy\",\n ruleId: \"policy-financial-app\",\n severity: \"warning\",\n title: \"Potential financial app detected\",\n message:\n \"App requests SMS + autofill permissions, common in financial apps. Financial apps must comply with additional disclosure and security requirements.\",\n suggestion:\n \"Ensure your app meets Google Play's financial services policy. Declare appropriate app category in Play Console.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/9876821\",\n });\n }\n\n // Health app indicators\n if (\n perms.has(\"android.permission.BODY_SENSORS\") ||\n perms.has(\"android.permission.ACTIVITY_RECOGNITION\")\n ) {\n findings.push({\n scanner: \"policy\",\n ruleId: \"policy-health-app\",\n severity: \"info\",\n title: \"Health/fitness app detected\",\n message:\n \"App requests body sensor or activity recognition permissions. Health apps must comply with health data policies.\",\n suggestion:\n \"Review Google Play's health app policy. Ensure accurate health claims and proper data handling disclosures.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/10787469\",\n });\n }\n\n // UGC indicators\n const ugcIndicators = [\n perms.has(\"android.permission.CAMERA\"),\n perms.has(\"android.permission.RECORD_AUDIO\"),\n perms.has(\"android.permission.READ_MEDIA_IMAGES\"),\n ];\n if (ugcIndicators.filter(Boolean).length >= 2) {\n findings.push({\n scanner: \"policy\",\n ruleId: \"policy-ugc-content\",\n severity: \"info\",\n title: \"User-generated content indicators\",\n message:\n \"App requests camera + audio/media permissions, suggesting user-generated content. Apps with UGC must have content moderation.\",\n suggestion:\n \"Implement content moderation, reporting mechanisms, and content policies if your app allows user-generated content.\",\n policyUrl: \"https://support.google.com/googleplay/android-developer/answer/9876937\",\n });\n }\n\n // System alert window / overlay\n if (perms.has(\"android.permission.SYSTEM_ALERT_WINDOW\")) {\n findings.push({\n scanner: \"policy\",\n ruleId: \"policy-overlay\",\n severity: \"warning\",\n title: \"SYSTEM_ALERT_WINDOW (overlay) permission\",\n message:\n \"App requests overlay permission. This is restricted and must be justified. Misuse can lead to rejection.\",\n suggestion:\n \"Only use SYSTEM_ALERT_WINDOW if overlay display is core to your app's functionality.\",\n });\n }\n\n return findings;\n },\n};\n","// Named exports only. No default export.\n\nimport type { PreflightScanner, PreflightContext, PreflightFinding } from \"../types.js\";\n\nexport const sizeScanner: PreflightScanner = {\n name: \"size\",\n description: \"Analyzes app bundle size and warns on large downloads\",\n requires: [\"zipEntries\"],\n\n async scan(ctx: PreflightContext): Promise<PreflightFinding[]> {\n const entries = ctx.zipEntries!;\n const findings: PreflightFinding[] = [];\n const maxMb = ctx.config.maxDownloadSizeMb;\n\n // Total compressed size (approximate download size)\n const totalCompressed = entries.reduce((sum, e) => sum + e.compressedSize, 0);\n const totalUncompressed = entries.reduce((sum, e) => sum + e.uncompressedSize, 0);\n const compressedMb = totalCompressed / (1024 * 1024);\n const uncompressedMb = totalUncompressed / (1024 * 1024);\n\n if (compressedMb > maxMb) {\n findings.push({\n scanner: \"size\",\n ruleId: \"size-over-limit\",\n severity: \"warning\",\n title: `Download size exceeds ${maxMb} MB`,\n message: `Compressed size is ${compressedMb.toFixed(1)} MB. Downloads over ${maxMb} MB show a mobile data warning to users, which reduces install rates.`,\n suggestion:\n \"Use Android App Bundles for split APKs, remove unused resources, enable R8/ProGuard, and compress assets.\",\n policyUrl: \"https://developer.android.com/topic/performance/reduce-apk-size\",\n });\n }\n\n // Per-category breakdown\n const categories = new Map<\n string,\n { compressed: number; uncompressed: number; count: number }\n >();\n for (const entry of entries) {\n const cat = detectCategory(entry.path);\n const existing = categories.get(cat) ?? { compressed: 0, uncompressed: 0, count: 0 };\n existing.compressed += entry.compressedSize;\n existing.uncompressed += entry.uncompressedSize;\n existing.count += 1;\n categories.set(cat, existing);\n }\n\n // Large native libs\n const nativeLibs = categories.get(\"native-libs\");\n if (nativeLibs && nativeLibs.compressed > 50 * 1024 * 1024) {\n findings.push({\n scanner: \"size\",\n ruleId: \"size-large-native\",\n severity: \"warning\",\n title: \"Large native libraries\",\n message: `Native libraries are ${(nativeLibs.compressed / (1024 * 1024)).toFixed(1)} MB (compressed). This is the largest contributor to download size.`,\n suggestion:\n \"Review which native libraries are bundled. Consider using dynamic feature modules for optional native code.\",\n });\n }\n\n // Large assets\n const assets = categories.get(\"assets\");\n if (assets && assets.compressed > 30 * 1024 * 1024) {\n findings.push({\n scanner: \"size\",\n ruleId: \"size-large-assets\",\n severity: \"info\",\n title: \"Large assets directory\",\n message: `Assets are ${(assets.compressed / (1024 * 1024)).toFixed(1)} MB (compressed). Consider using Play Asset Delivery for large assets.`,\n suggestion:\n \"Move large assets to Play Asset Delivery (install-time, fast-follow, or on-demand packs).\",\n policyUrl: \"https://developer.android.com/guide/playcore/asset-delivery\",\n });\n }\n\n // Summary\n const breakdown = [...categories.entries()]\n .sort((a, b) => b[1].compressed - a[1].compressed)\n .map(([cat, data]) => `${cat}: ${(data.compressed / (1024 * 1024)).toFixed(1)} MB`)\n .join(\", \");\n\n findings.push({\n scanner: \"size\",\n ruleId: \"size-summary\",\n severity: \"info\",\n title: `Total size: ${compressedMb.toFixed(1)} MB compressed, ${uncompressedMb.toFixed(1)} MB uncompressed`,\n message: `${entries.length} files. Breakdown: ${breakdown}`,\n });\n\n return findings;\n },\n};\n\nfunction detectCategory(path: string): string {\n const lower = path.toLowerCase();\n if (lower.endsWith(\".dex\") || /\\/dex\\//.test(lower)) return \"dex\";\n if (/\\/lib\\/[^/]+\\/[^/]+\\.so$/.test(lower)) return \"native-libs\";\n if (/\\/res\\//.test(lower) || lower.endsWith(\"/resources.pb\") || lower.endsWith(\"/resources.arsc\"))\n return \"resources\";\n if (/\\/assets\\//.test(lower)) return \"assets\";\n if (lower.includes(\"androidmanifest.xml\") || /\\/manifest\\//.test(lower)) return \"manifest\";\n if (lower.startsWith(\"meta-inf/\")) return \"signing\";\n return \"other\";\n}\n","// Named exports only. No default export.\n\nimport type {\n PreflightOptions,\n PreflightResult,\n PreflightContext,\n PreflightScanner,\n PreflightFinding,\n FindingSeverity,\n} from \"./types.js\";\nimport { SEVERITY_ORDER, DEFAULT_PREFLIGHT_CONFIG } from \"./types.js\";\nimport { loadPreflightConfig } from \"./config.js\";\nimport { readAab } from \"./aab-reader.js\";\nimport { manifestScanner } from \"./scanners/manifest-scanner.js\";\nimport { permissionsScanner } from \"./scanners/permissions-scanner.js\";\nimport { nativeLibsScanner } from \"./scanners/native-libs-scanner.js\";\nimport { metadataScanner } from \"./scanners/metadata-scanner.js\";\nimport { secretsScanner } from \"./scanners/secrets-scanner.js\";\nimport { billingScanner } from \"./scanners/billing-scanner.js\";\nimport { privacyScanner } from \"./scanners/privacy-scanner.js\";\nimport { policyScanner } from \"./scanners/policy-scanner.js\";\nimport { sizeScanner } from \"./scanners/size-scanner.js\";\n\n/** All registered scanners. New scanners are added here. */\nconst ALL_SCANNERS: PreflightScanner[] = [\n manifestScanner,\n permissionsScanner,\n nativeLibsScanner,\n metadataScanner,\n secretsScanner,\n billingScanner,\n privacyScanner,\n policyScanner,\n sizeScanner,\n];\n\nexport function getAllScannerNames(): string[] {\n return ALL_SCANNERS.map((s) => s.name);\n}\n\nexport async function runPreflight(options: PreflightOptions): Promise<PreflightResult> {\n const start = Date.now();\n\n // Load config (file + CLI overrides)\n const fileConfig = await loadPreflightConfig(options.configPath);\n const config = {\n ...fileConfig,\n failOn: options.failOn ?? fileConfig.failOn ?? DEFAULT_PREFLIGHT_CONFIG.failOn,\n };\n\n // Build context\n const ctx: PreflightContext = { config };\n\n // Open AAB if provided\n const earlyFindings: PreflightFinding[] = [];\n if (options.aabPath) {\n ctx.aabPath = options.aabPath;\n const aab = await readAab(options.aabPath);\n ctx.manifest = aab.manifest;\n ctx.zipEntries = aab.entries;\n\n // If manifest had a parse error, emit a warning and clear manifest\n // so manifest-dependent scanners are skipped gracefully\n if (aab.manifest._parseError) {\n earlyFindings.push({\n scanner: \"manifest-parser\",\n ruleId: \"manifest-parse-error\",\n severity: \"warning\",\n title: \"Manifest could not be fully parsed\",\n message: aab.manifest._parseError,\n suggestion: \"Manifest-dependent scanners (manifest, permissions, policy, privacy) were skipped. Other scanners (native-libs, size, secrets, billing) still ran.\",\n });\n ctx.manifest = undefined;\n }\n }\n\n if (options.metadataDir) ctx.metadataDir = options.metadataDir;\n if (options.sourceDir) ctx.sourceDir = options.sourceDir;\n\n // Filter scanners\n const requestedNames = options.scanners\n ? new Set(options.scanners.map((s) => s.toLowerCase()))\n : null;\n\n const applicableScanners = ALL_SCANNERS.filter((scanner) => {\n // Filter by name if specified\n if (requestedNames && !requestedNames.has(scanner.name)) return false;\n\n // Filter by context availability\n for (const req of scanner.requires) {\n if (req === \"manifest\" && !ctx.manifest) return false;\n if (req === \"zipEntries\" && !ctx.zipEntries) return false;\n if (req === \"metadataDir\" && !ctx.metadataDir) return false;\n if (req === \"sourceDir\" && !ctx.sourceDir) return false;\n }\n\n return true;\n });\n\n // Run all applicable scanners in parallel — use allSettled so one failure doesn't stop others\n const settled = await Promise.allSettled(applicableScanners.map((scanner) => scanner.scan(ctx)));\n\n // Flatten findings, report scanner failures as error findings\n let findings: PreflightFinding[] = [...earlyFindings];\n for (let i = 0; i < settled.length; i++) {\n const result = settled[i]!;\n if (result.status === \"fulfilled\") {\n findings.push(...result.value);\n } else {\n const scanner = applicableScanners[i]!;\n findings.push({\n scanner: scanner.name,\n ruleId: \"scanner-error\",\n severity: \"error\",\n title: `Scanner \"${scanner.name}\" failed`,\n message: result.reason instanceof Error ? result.reason.message : String(result.reason),\n suggestion: \"This scanner encountered an unexpected error. Other scanners still ran.\",\n });\n }\n }\n\n // Apply disabled rules\n if (config.disabledRules.length > 0) {\n const disabled = new Set(config.disabledRules);\n findings = findings.filter((f) => !disabled.has(f.ruleId));\n }\n\n // Apply severity overrides\n if (Object.keys(config.severityOverrides).length > 0) {\n findings = findings.map((f) => {\n const override = config.severityOverrides[f.ruleId];\n return override ? { ...f, severity: override } : f;\n });\n }\n\n // Sort by severity (critical first)\n findings.sort((a, b) => SEVERITY_ORDER[b.severity] - SEVERITY_ORDER[a.severity]);\n\n // Compute summary\n const summary: Record<FindingSeverity, number> = { critical: 0, error: 0, warning: 0, info: 0 };\n for (const f of findings) summary[f.severity]++;\n\n // Check pass/fail threshold\n const failThreshold = SEVERITY_ORDER[config.failOn];\n const passed = !findings.some((f) => SEVERITY_ORDER[f.severity] >= failThreshold);\n\n return {\n scanners: applicableScanners.map((s) => s.name),\n findings,\n summary,\n passed,\n durationMs: Date.now() - start,\n };\n}\n","/**\n * Sort utility for CLI list command results.\n *\n * Supports ascending (field) and descending (-field) sort specs,\n * including dot notation for nested fields (e.g., \"comments.userComment.starRating\").\n */\n\nfunction getNestedValue(obj: unknown, path: string): unknown {\n const parts = path.split(\".\");\n let current: unknown = obj;\n for (const part of parts) {\n if (current === null || current === undefined || typeof current !== \"object\") {\n return undefined;\n }\n current = (current as Record<string, unknown>)[part];\n }\n return current;\n}\n\nfunction compare(a: unknown, b: unknown): number {\n if (a === undefined && b === undefined) return 0;\n if (a === undefined) return 1;\n if (b === undefined) return -1;\n\n if (typeof a === \"number\" && typeof b === \"number\") {\n return a - b;\n }\n\n return String(a).localeCompare(String(b));\n}\n\n/**\n * Sort an array of items by a field specification.\n *\n * @param items - Array to sort (not mutated; returns a new array)\n * @param sortSpec - Field name for ascending, or `-field` for descending.\n * Supports dot notation for nested fields.\n * If undefined/empty, returns items in original order.\n * @returns Sorted copy of items\n */\nexport function sortResults<T>(items: T[], sortSpec?: string): T[] {\n if (!sortSpec || items.length === 0) {\n return items;\n }\n\n const descending = sortSpec.startsWith(\"-\");\n const field = descending ? sortSpec.slice(1) : sortSpec;\n\n // Validate that at least one item has the field — if none do, return original order\n const hasField = items.some((item) => getNestedValue(item, field) !== undefined);\n if (!hasField) {\n return items;\n }\n\n const sorted = [...items].sort((a, b) => {\n const aVal = getNestedValue(a, field);\n const bVal = getNestedValue(b, field);\n const result = compare(aVal, bVal);\n return descending ? -result : result;\n });\n\n return sorted;\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport interface ScaffoldOptions {\n name: string;\n dir: string;\n description?: string;\n}\n\nexport interface ScaffoldResult {\n dir: string;\n files: string[];\n}\n\n/**\n * Scaffold a new GPC plugin project.\n */\nexport async function scaffoldPlugin(options: ScaffoldOptions): Promise<ScaffoldResult> {\n const { name, dir, description = `GPC plugin: ${name}` } = options;\n\n // Ensure name follows convention\n const pluginName = name.startsWith(\"gpc-plugin-\") ? name : `gpc-plugin-${name}`;\n const shortName = pluginName.replace(/^gpc-plugin-/, \"\");\n\n const srcDir = join(dir, \"src\");\n const testDir = join(dir, \"tests\");\n\n await mkdir(srcDir, { recursive: true });\n await mkdir(testDir, { recursive: true });\n\n const files: string[] = [];\n\n // package.json\n const pkg = {\n name: pluginName,\n version: \"0.1.0\",\n description,\n type: \"module\",\n main: \"./dist/index.js\",\n types: \"./dist/index.d.ts\",\n exports: {\n \".\": {\n import: \"./dist/index.js\",\n types: \"./dist/index.d.ts\",\n },\n },\n files: [\"dist\"],\n scripts: {\n build: \"tsup src/index.ts --format esm --dts\",\n dev: \"tsup src/index.ts --format esm --dts --watch\",\n test: \"vitest run\",\n \"test:watch\": \"vitest\",\n },\n keywords: [\"gpc\", \"gpc-plugin\", \"google-play\"],\n license: \"MIT\",\n peerDependencies: {\n \"@gpc-cli/plugin-sdk\": \">=0.8.0\",\n },\n devDependencies: {\n \"@gpc-cli/plugin-sdk\": \"^0.8.0\",\n tsup: \"^8.0.0\",\n typescript: \"^5.0.0\",\n vitest: \"^3.0.0\",\n },\n };\n await writeFile(join(dir, \"package.json\"), JSON.stringify(pkg, null, 2) + \"\\n\");\n files.push(\"package.json\");\n\n // tsconfig.json\n const tsconfig = {\n compilerOptions: {\n target: \"ES2022\",\n module: \"ESNext\",\n moduleResolution: \"bundler\",\n declaration: true,\n strict: true,\n esModuleInterop: true,\n skipLibCheck: true,\n outDir: \"./dist\",\n rootDir: \"./src\",\n },\n include: [\"src\"],\n };\n await writeFile(join(dir, \"tsconfig.json\"), JSON.stringify(tsconfig, null, 2) + \"\\n\");\n files.push(\"tsconfig.json\");\n\n // src/index.ts\n const srcContent = `import { definePlugin } from \"@gpc-cli/plugin-sdk\";\nimport type { CommandEvent, CommandResult } from \"@gpc-cli/plugin-sdk\";\n\nexport const plugin = definePlugin({\n name: \"${pluginName}\",\n version: \"0.1.0\",\n\n register(hooks) {\n hooks.beforeCommand(async (event: CommandEvent) => {\n // Called before every gpc command\n // Example: log command usage, validate prerequisites, etc.\n });\n\n hooks.afterCommand(async (event: CommandEvent, result: CommandResult) => {\n // Called after every successful gpc command\n // Example: send notifications, update dashboards, etc.\n });\n\n // Uncomment to add custom commands:\n // hooks.registerCommands((registry) => {\n // registry.add({\n // name: \"${shortName}\",\n // description: \"${description}\",\n // action: async (args, opts) => {\n // console.log(\"Hello from ${pluginName}!\");\n // },\n // });\n // });\n },\n});\n`;\n await writeFile(join(srcDir, \"index.ts\"), srcContent);\n files.push(\"src/index.ts\");\n\n // tests/plugin.test.ts\n const testContent = `import { describe, it, expect, vi } from \"vitest\";\nimport { plugin } from \"../src/index\";\n\ndescribe(\"${pluginName}\", () => {\n it(\"has correct name and version\", () => {\n expect(plugin.name).toBe(\"${pluginName}\");\n expect(plugin.version).toBe(\"0.1.0\");\n });\n\n it(\"registers without errors\", () => {\n const hooks = {\n beforeCommand: vi.fn(),\n afterCommand: vi.fn(),\n onError: vi.fn(),\n beforeRequest: vi.fn(),\n afterResponse: vi.fn(),\n registerCommands: vi.fn(),\n };\n\n expect(() => plugin.register(hooks)).not.toThrow();\n });\n});\n`;\n await writeFile(join(testDir, \"plugin.test.ts\"), testContent);\n files.push(\"tests/plugin.test.ts\");\n\n return { dir, files };\n}\n","import type { WebhookConfig } from \"@gpc-cli/config\";\n\nexport interface WebhookPayload {\n command: string;\n success: boolean;\n duration: number;\n app?: string;\n details?: Record<string, unknown>;\n error?: string;\n}\n\nexport function formatSlackPayload(payload: WebhookPayload): object {\n const status = payload.success ? \"\\u2713\" : \"\\u2717\";\n const color = payload.success ? \"#2eb886\" : \"#e01e5a\";\n const durationSec = (payload.duration / 1000).toFixed(1);\n\n const fields: Array<{ title: string; value: string; short: boolean }> = [\n { title: \"Command\", value: payload.command, short: true },\n { title: \"Duration\", value: `${durationSec}s`, short: true },\n ];\n\n if (payload.app) {\n fields.push({ title: \"App\", value: payload.app, short: true });\n }\n\n if (payload.error) {\n fields.push({ title: \"Error\", value: payload.error, short: false });\n }\n\n if (payload.details) {\n for (const [key, value] of Object.entries(payload.details)) {\n fields.push({ title: key, value: String(value), short: true });\n }\n }\n\n return {\n attachments: [\n {\n color,\n fallback: `GPC: ${payload.command} ${status}`,\n title: `GPC: ${payload.command} ${status}`,\n fields,\n footer: \"GPC CLI\",\n ts: Math.floor(Date.now() / 1000),\n },\n ],\n };\n}\n\nexport function formatDiscordPayload(payload: WebhookPayload): object {\n const status = payload.success ? \"\\u2713\" : \"\\u2717\";\n const color = payload.success ? 0x2eb886 : 0xe01e5a;\n const durationSec = (payload.duration / 1000).toFixed(1);\n\n const fields: Array<{ name: string; value: string; inline: boolean }> = [\n { name: \"Command\", value: payload.command, inline: true },\n { name: \"Duration\", value: `${durationSec}s`, inline: true },\n ];\n\n if (payload.app) {\n fields.push({ name: \"App\", value: payload.app, inline: true });\n }\n\n if (payload.error) {\n fields.push({ name: \"Error\", value: payload.error, inline: false });\n }\n\n if (payload.details) {\n for (const [key, value] of Object.entries(payload.details)) {\n fields.push({ name: key, value: String(value), inline: true });\n }\n }\n\n return {\n embeds: [\n {\n title: `GPC: ${payload.command} ${status}`,\n color,\n fields,\n footer: { text: \"GPC CLI\" },\n timestamp: new Date().toISOString(),\n },\n ],\n };\n}\n\nexport function formatCustomPayload(payload: WebhookPayload): object {\n return { ...payload };\n}\n\ntype WebhookTarget = \"slack\" | \"discord\" | \"custom\";\n\nconst FORMATTERS: Record<WebhookTarget, (p: WebhookPayload) => object> = {\n slack: formatSlackPayload,\n discord: formatDiscordPayload,\n custom: formatCustomPayload,\n};\n\nconst WEBHOOK_TIMEOUT_MS = 5000;\n\nasync function sendSingle(url: string, body: object): Promise<void> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), WEBHOOK_TIMEOUT_MS);\n\n try {\n await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function sendWebhook(\n config: WebhookConfig,\n payload: WebhookPayload,\n target?: string,\n): Promise<void> {\n try {\n const targets: WebhookTarget[] = target\n ? [target as WebhookTarget]\n : (Object.keys(FORMATTERS) as WebhookTarget[]);\n\n const promises: Promise<void>[] = [];\n\n for (const t of targets) {\n const url = config[t];\n if (!url) continue;\n\n const formatter = FORMATTERS[t];\n if (!formatter) continue;\n\n const body = formatter(payload);\n promises.push(sendSingle(url, body).catch(() => {}));\n }\n\n await Promise.all(promises);\n } catch {\n // Never throw — webhook failures must not break the CLI\n }\n}\n","import { extname } from \"node:path\";\nimport type { PlayApiClient, InternalAppSharingArtifact } from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\nimport { validateUploadFile } from \"../utils/file-validation.js\";\n\nexport interface InternalSharingUploadResult {\n downloadUrl: string;\n sha256: string;\n certificateFingerprint: string;\n fileType: \"bundle\" | \"apk\";\n}\n\nexport async function uploadInternalSharing(\n client: PlayApiClient,\n packageName: string,\n filePath: string,\n fileType?: \"bundle\" | \"apk\",\n): Promise<InternalSharingUploadResult> {\n // Auto-detect file type from extension if not provided\n const resolvedType = fileType ?? detectFileType(filePath);\n\n // Validate the file\n const validation = await validateUploadFile(filePath);\n if (!validation.valid) {\n throw new GpcError(\n `File validation failed:\\n${validation.errors.join(\"\\n\")}`,\n \"INTERNAL_SHARING_INVALID_FILE\",\n 2,\n \"Check that the file is a valid AAB or APK and is not corrupted.\",\n );\n }\n\n let artifact: InternalAppSharingArtifact;\n if (resolvedType === \"bundle\") {\n artifact = await client.internalAppSharing.uploadBundle(packageName, filePath);\n } else {\n artifact = await client.internalAppSharing.uploadApk(packageName, filePath);\n }\n\n return {\n downloadUrl: artifact.downloadUrl,\n sha256: artifact.sha256,\n certificateFingerprint: artifact.certificateFingerprint,\n fileType: resolvedType,\n };\n}\n\nfunction detectFileType(filePath: string): \"bundle\" | \"apk\" {\n const ext = extname(filePath).toLowerCase();\n if (ext === \".aab\") return \"bundle\";\n if (ext === \".apk\") return \"apk\";\n throw new GpcError(\n `Cannot detect file type from extension \"${ext}\". Use --type to specify bundle or apk.`,\n \"INTERNAL_SHARING_UNKNOWN_TYPE\",\n 2,\n \"Use --type bundle for .aab files or --type apk for .apk files.\",\n );\n}\n","import { writeFile } from \"node:fs/promises\";\nimport type { PlayApiClient, GeneratedApk } from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\n\nexport async function listGeneratedApks(\n client: PlayApiClient,\n packageName: string,\n versionCode: number,\n): Promise<GeneratedApk[]> {\n if (!Number.isInteger(versionCode) || versionCode <= 0) {\n throw new GpcError(\n `Invalid version code: ${versionCode}`,\n \"GENERATED_APKS_INVALID_VERSION\",\n 2,\n \"Provide a positive integer version code.\",\n );\n }\n return client.generatedApks.list(packageName, versionCode);\n}\n\nexport async function downloadGeneratedApk(\n client: PlayApiClient,\n packageName: string,\n versionCode: number,\n apkId: string,\n outputPath: string,\n): Promise<{ path: string; sizeBytes: number }> {\n if (!Number.isInteger(versionCode) || versionCode <= 0) {\n throw new GpcError(\n `Invalid version code: ${versionCode}`,\n \"GENERATED_APKS_INVALID_VERSION\",\n 2,\n \"Provide a positive integer version code.\",\n );\n }\n\n if (!apkId) {\n throw new GpcError(\n \"APK ID is required\",\n \"GENERATED_APKS_MISSING_ID\",\n 2,\n \"Provide the generated APK ID. Use 'gpc generated-apks list <version-code>' to see available APKs.\",\n );\n }\n\n const buffer = await client.generatedApks.download(packageName, versionCode, apkId);\n const bytes = new Uint8Array(buffer);\n await writeFile(outputPath, bytes);\n\n return { path: outputPath, sizeBytes: bytes.byteLength };\n}\n","import type { PlayApiClient, PurchaseOption, PurchaseOptionsListResponse } from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\n\nexport async function listPurchaseOptions(\n client: PlayApiClient,\n packageName: string,\n): Promise<PurchaseOptionsListResponse> {\n try {\n return await client.purchaseOptions.list(packageName);\n } catch (error) {\n throw new GpcError(\n `Failed to list purchase options: ${error instanceof Error ? error.message : String(error)}`,\n \"PURCHASE_OPTIONS_LIST_FAILED\",\n 4,\n \"Check your package name and API permissions.\",\n );\n }\n}\n\nexport async function getPurchaseOption(\n client: PlayApiClient,\n packageName: string,\n purchaseOptionId: string,\n): Promise<PurchaseOption> {\n try {\n return await client.purchaseOptions.get(packageName, purchaseOptionId);\n } catch (error) {\n throw new GpcError(\n `Failed to get purchase option \"${purchaseOptionId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"PURCHASE_OPTION_GET_FAILED\",\n 4,\n \"Check that the purchase option ID exists.\",\n );\n }\n}\n\nexport async function createPurchaseOption(\n client: PlayApiClient,\n packageName: string,\n data: PurchaseOption,\n): Promise<PurchaseOption> {\n try {\n return await client.purchaseOptions.create(packageName, data);\n } catch (error) {\n throw new GpcError(\n `Failed to create purchase option: ${error instanceof Error ? error.message : String(error)}`,\n \"PURCHASE_OPTION_CREATE_FAILED\",\n 4,\n \"Check your purchase option data and API permissions.\",\n );\n }\n}\n\nexport async function activatePurchaseOption(\n client: PlayApiClient,\n packageName: string,\n purchaseOptionId: string,\n): Promise<PurchaseOption> {\n try {\n return await client.purchaseOptions.activate(packageName, purchaseOptionId);\n } catch (error) {\n throw new GpcError(\n `Failed to activate purchase option \"${purchaseOptionId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"PURCHASE_OPTION_ACTIVATE_FAILED\",\n 4,\n \"Check that the purchase option exists and is in a valid state for activation.\",\n );\n }\n}\n\nexport async function deactivatePurchaseOption(\n client: PlayApiClient,\n packageName: string,\n purchaseOptionId: string,\n): Promise<PurchaseOption> {\n try {\n return await client.purchaseOptions.deactivate(packageName, purchaseOptionId);\n } catch (error) {\n throw new GpcError(\n `Failed to deactivate purchase option \"${purchaseOptionId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"PURCHASE_OPTION_DEACTIVATE_FAILED\",\n 4,\n \"Check that the purchase option exists and is in a valid state for deactivation.\",\n );\n }\n}\n","import { readFile, stat } from \"node:fs/promises\";\n\nexport interface BundleEntry {\n path: string;\n module: string;\n category: string;\n compressedSize: number;\n uncompressedSize: number;\n}\n\nexport interface BundleAnalysis {\n filePath: string;\n fileType: \"aab\" | \"apk\";\n totalCompressed: number;\n totalUncompressed: number;\n entryCount: number;\n modules: { name: string; compressedSize: number; uncompressedSize: number; entries: number }[];\n categories: { name: string; compressedSize: number; uncompressedSize: number; entries: number }[];\n entries: BundleEntry[];\n}\n\nexport interface BundleComparison {\n before: { path: string; totalCompressed: number };\n after: { path: string; totalCompressed: number };\n sizeDelta: number;\n sizeDeltaPercent: number;\n moduleDeltas: { module: string; before: number; after: number; delta: number }[];\n categoryDeltas: { category: string; before: number; after: number; delta: number }[];\n}\n\nconst EOCD_SIGNATURE = 0x06054b50;\nconst CD_SIGNATURE = 0x02014b50;\n\n/** Known AAB module subdirs that distinguish feature modules from arbitrary top-level dirs. */\nconst MODULE_SUBDIRS = new Set([\"dex\", \"manifest\", \"res\", \"assets\", \"lib\", \"resources.pb\", \"root\"]);\n\nfunction detectCategory(path: string): string {\n const lower = path.toLowerCase();\n // dex files\n if (lower.endsWith(\".dex\") || /\\/dex\\/[^/]+\\.dex$/.test(lower)) return \"dex\";\n // resources\n if (\n lower === \"resources.arsc\" ||\n lower.endsWith(\"/resources.arsc\") ||\n lower.endsWith(\"/resources.pb\") ||\n /^(([^/]+\\/)?res\\/)/.test(lower)\n )\n return \"resources\";\n // assets\n if (/^(([^/]+\\/)?assets\\/)/.test(lower)) return \"assets\";\n // native libs\n if (/^(([^/]+\\/)?lib\\/)/.test(lower)) return \"native-libs\";\n // manifest\n if (\n lower === \"androidmanifest.xml\" ||\n lower.endsWith(\"/androidmanifest.xml\") ||\n /^(([^/]+\\/)?manifest\\/)/.test(lower)\n )\n return \"manifest\";\n // signing\n if (lower.startsWith(\"meta-inf/\") || lower === \"meta-inf\") return \"signing\";\n return \"other\";\n}\n\nfunction detectModule(path: string, isAab: boolean): string {\n if (!isAab) return \"(root)\";\n\n const slashIdx = path.indexOf(\"/\");\n if (slashIdx === -1) return \"(root)\";\n\n const topDir = path.substring(0, slashIdx);\n const rest = path.substring(slashIdx + 1);\n\n // \"base/\" module\n if (topDir === \"base\") return \"base\";\n\n // Root-level metadata\n if (topDir === \"BUNDLE-METADATA\" || topDir === \"META-INF\") return \"(root)\";\n if (path === \"BundleConfig.pb\") return \"(root)\";\n\n // Check if subdirectory matches known module structure\n const subDir = rest.split(\"/\")[0] || \"\";\n if (MODULE_SUBDIRS.has(subDir)) return topDir;\n\n return \"(root)\";\n}\n\ninterface CentralDirectoryEntry {\n filename: string;\n compressedSize: number;\n uncompressedSize: number;\n}\n\nfunction parseCentralDirectory(buf: Buffer): CentralDirectoryEntry[] {\n // Find EOCD — scan backwards from end (minimum EOCD is 22 bytes)\n let eocdOffset = -1;\n for (let i = buf.length - 22; i >= 0 && i >= buf.length - 65557; i--) {\n if (buf.readUInt32LE(i) === EOCD_SIGNATURE) {\n eocdOffset = i;\n break;\n }\n }\n if (eocdOffset === -1) {\n throw new Error(\"Not a valid ZIP file: EOCD signature not found\");\n }\n\n const cdSize = buf.readUInt32LE(eocdOffset + 12);\n let cdOffset = buf.readUInt32LE(eocdOffset + 16);\n\n // Handle ZIP64 — if offset is 0xFFFFFFFF, look for ZIP64 EOCD locator\n if (cdOffset === 0xffffffff) {\n // ZIP64 end of central directory locator is 20 bytes before EOCD\n const zip64LocatorOffset = eocdOffset - 20;\n if (zip64LocatorOffset >= 0 && buf.readUInt32LE(zip64LocatorOffset) === 0x07064b50) {\n // ZIP64 EOCD is at offset stored in locator bytes 8-15\n const zip64EocdOffset = Number(buf.readBigUInt64LE(zip64LocatorOffset + 8));\n if (zip64EocdOffset >= 0 && zip64EocdOffset < buf.length) {\n cdOffset = Number(buf.readBigUInt64LE(zip64EocdOffset + 48));\n }\n }\n }\n\n const entries: CentralDirectoryEntry[] = [];\n let pos = cdOffset;\n const end = cdOffset + cdSize;\n\n while (pos < end && pos + 46 <= buf.length) {\n const sig = buf.readUInt32LE(pos);\n if (sig !== CD_SIGNATURE) break;\n\n const compressedSize = buf.readUInt32LE(pos + 20);\n const uncompressedSize = buf.readUInt32LE(pos + 24);\n const filenameLen = buf.readUInt16LE(pos + 28);\n const extraLen = buf.readUInt16LE(pos + 30);\n const commentLen = buf.readUInt16LE(pos + 32);\n\n const filename = buf.toString(\"utf-8\", pos + 46, pos + 46 + filenameLen);\n\n // Skip directory entries (trailing slash)\n if (!filename.endsWith(\"/\")) {\n entries.push({ filename, compressedSize, uncompressedSize });\n }\n\n pos += 46 + filenameLen + extraLen + commentLen;\n }\n\n return entries;\n}\n\nfunction detectFileType(filePath: string): \"aab\" | \"apk\" {\n const lower = filePath.toLowerCase();\n if (lower.endsWith(\".aab\")) return \"aab\";\n return \"apk\";\n}\n\nexport async function analyzeBundle(filePath: string): Promise<BundleAnalysis> {\n const fileInfo = await stat(filePath).catch(() => null);\n if (!fileInfo || !fileInfo.isFile()) {\n throw new Error(`File not found: ${filePath}`);\n }\n\n const buf = await readFile(filePath);\n const cdEntries = parseCentralDirectory(buf);\n const fileType = detectFileType(filePath);\n const isAab = fileType === \"aab\";\n\n const entries: BundleEntry[] = cdEntries.map((e) => ({\n path: e.filename,\n module: detectModule(e.filename, isAab),\n category: detectCategory(e.filename),\n compressedSize: e.compressedSize,\n uncompressedSize: e.uncompressedSize,\n }));\n\n // Aggregate by module\n const moduleMap = new Map<\n string,\n { compressedSize: number; uncompressedSize: number; entries: number }\n >();\n for (const entry of entries) {\n const existing = moduleMap.get(entry.module) ?? {\n compressedSize: 0,\n uncompressedSize: 0,\n entries: 0,\n };\n existing.compressedSize += entry.compressedSize;\n existing.uncompressedSize += entry.uncompressedSize;\n existing.entries += 1;\n moduleMap.set(entry.module, existing);\n }\n\n // Aggregate by category\n const categoryMap = new Map<\n string,\n { compressedSize: number; uncompressedSize: number; entries: number }\n >();\n for (const entry of entries) {\n const existing = categoryMap.get(entry.category) ?? {\n compressedSize: 0,\n uncompressedSize: 0,\n entries: 0,\n };\n existing.compressedSize += entry.compressedSize;\n existing.uncompressedSize += entry.uncompressedSize;\n existing.entries += 1;\n categoryMap.set(entry.category, existing);\n }\n\n const modules = [...moduleMap.entries()]\n .map(([name, data]) => ({ name, ...data }))\n .sort((a, b) => b.compressedSize - a.compressedSize);\n\n const categories = [...categoryMap.entries()]\n .map(([name, data]) => ({ name, ...data }))\n .sort((a, b) => b.compressedSize - a.compressedSize);\n\n const totalCompressed = entries.reduce((sum, e) => sum + e.compressedSize, 0);\n const totalUncompressed = entries.reduce((sum, e) => sum + e.uncompressedSize, 0);\n\n return {\n filePath,\n fileType,\n totalCompressed,\n totalUncompressed,\n entryCount: entries.length,\n modules,\n categories,\n entries,\n };\n}\n\nexport function compareBundles(before: BundleAnalysis, after: BundleAnalysis): BundleComparison {\n const sizeDelta = after.totalCompressed - before.totalCompressed;\n const sizeDeltaPercent =\n before.totalCompressed > 0\n ? Math.round((sizeDelta / before.totalCompressed) * 100 * 10) / 10\n : 0;\n\n // Module deltas\n const allModules = new Set([\n ...before.modules.map((m) => m.name),\n ...after.modules.map((m) => m.name),\n ]);\n const moduleDeltas = [...allModules]\n .map((module) => {\n const b = before.modules.find((m) => m.name === module)?.compressedSize ?? 0;\n const a = after.modules.find((m) => m.name === module)?.compressedSize ?? 0;\n return { module, before: b, after: a, delta: a - b };\n })\n .sort((a, b) => Math.abs(b.delta) - Math.abs(a.delta));\n\n // Category deltas\n const allCategories = new Set([\n ...before.categories.map((c) => c.name),\n ...after.categories.map((c) => c.name),\n ]);\n const categoryDeltas = [...allCategories]\n .map((category) => {\n const b = before.categories.find((c) => c.name === category)?.compressedSize ?? 0;\n const a = after.categories.find((c) => c.name === category)?.compressedSize ?? 0;\n return { category, before: b, after: a, delta: a - b };\n })\n .sort((a, b) => Math.abs(b.delta) - Math.abs(a.delta));\n\n return {\n before: { path: before.filePath, totalCompressed: before.totalCompressed },\n after: { path: after.filePath, totalCompressed: after.totalCompressed },\n sizeDelta,\n sizeDeltaPercent,\n moduleDeltas,\n categoryDeltas,\n };\n}\n\n/** Return the top N largest files by compressed size. */\nexport function topFiles(analysis: BundleAnalysis, n: number = 20): BundleEntry[] {\n return [...analysis.entries].sort((a, b) => b.compressedSize - a.compressedSize).slice(0, n);\n}\n\nexport interface BundleSizeConfig {\n maxTotalCompressed?: number;\n modules?: Record<string, { maxCompressed: number }>;\n}\n\nexport interface BundleSizeCheckResult {\n passed: boolean;\n violations: Array<{ subject: string; actual: number; max: number }>;\n}\n\n/** Check bundle analysis against .bundlesize.json thresholds. */\nexport async function checkBundleSize(\n analysis: BundleAnalysis,\n configPath: string = \".bundlesize.json\",\n): Promise<BundleSizeCheckResult> {\n let config: BundleSizeConfig;\n try {\n const raw = await readFile(configPath, \"utf-8\");\n config = JSON.parse(raw) as BundleSizeConfig;\n } catch {\n return { passed: true, violations: [] };\n }\n\n const violations: BundleSizeCheckResult[\"violations\"] = [];\n\n if (\n config.maxTotalCompressed !== undefined &&\n analysis.totalCompressed > config.maxTotalCompressed\n ) {\n violations.push({\n subject: \"total\",\n actual: analysis.totalCompressed,\n max: config.maxTotalCompressed,\n });\n }\n\n if (config.modules) {\n for (const [moduleName, threshold] of Object.entries(config.modules)) {\n const mod = analysis.modules.find((m) => m.name === moduleName);\n if (mod && mod.compressedSize > threshold.maxCompressed) {\n violations.push({\n subject: `module:${moduleName}`,\n actual: mod.compressedSize,\n max: threshold.maxCompressed,\n });\n }\n }\n }\n\n return { passed: violations.length === 0, violations };\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { execFile } from \"node:child_process\";\nimport { join } from \"node:path\";\nimport type { PlayApiClient } from \"@gpc-cli/api\";\nimport type { ReportingApiClient } from \"@gpc-cli/api\";\nimport { getCacheDir } from \"@gpc-cli/config\";\nimport { GpcError } from \"../errors.js\";\nimport { getReleasesStatus } from \"./releases.js\";\nimport { listReviews } from \"./reviews.js\";\nimport type { VitalsMetricSet, MetricSetQuery } from \"@gpc-cli/api\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface StatusVitalMetric {\n value: number | undefined;\n threshold: number;\n status: \"ok\" | \"warn\" | \"breach\" | \"unknown\";\n previousValue?: number | undefined;\n trend?: \"up\" | \"down\" | \"flat\" | null;\n}\n\nexport interface StatusRelease {\n track: string;\n versionCode: string;\n status: string;\n userFraction: number | null;\n}\n\nexport interface StatusReviews {\n windowDays: number;\n averageRating: number | undefined;\n previousAverageRating: number | undefined;\n totalNew: number;\n positivePercent: number | undefined;\n}\n\nexport interface AppStatus {\n packageName: string;\n fetchedAt: string;\n cached: boolean;\n sections: string[]; // active sections: \"releases\" | \"vitals\" | \"reviews\"\n releases: StatusRelease[];\n vitals: {\n windowDays: number;\n crashes: StatusVitalMetric;\n anr: StatusVitalMetric;\n slowStarts: StatusVitalMetric;\n slowRender: StatusVitalMetric;\n };\n reviews: StatusReviews;\n}\n\nexport interface StatusDiff {\n versionCode: { from: string | null; to: string | null };\n crashRate: { from: number | null; to: number | null; delta: number | null };\n anrRate: { from: number | null; to: number | null; delta: number | null };\n reviewCount: { from: number | null; to: number | null };\n averageRating: { from: number | null; to: number | null; delta: number | null };\n}\n\nexport interface GetAppStatusOptions {\n days?: number;\n reviewDays?: number;\n sections?: string[]; // \"releases\" | \"vitals\" | \"reviews\"\n vitalThresholds?: {\n crashRate?: number;\n anrRate?: number;\n slowStartRate?: number;\n slowRenderingRate?: number;\n };\n}\n\nexport interface WatchOptions {\n intervalSeconds: number;\n render: (status: AppStatus) => string;\n fetch: () => Promise<AppStatus>;\n save: (status: AppStatus) => Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// Cache\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_TTL_SECONDS = 3600;\n\ninterface CacheEntry {\n fetchedAt: string;\n ttl: number;\n data: AppStatus;\n}\n\nfunction cacheFilePath(packageName: string): string {\n return join(getCacheDir(), `status-${packageName}.json`);\n}\n\nexport async function loadStatusCache(\n packageName: string,\n ttlSeconds = DEFAULT_TTL_SECONDS,\n): Promise<AppStatus | null> {\n try {\n const raw = await readFile(cacheFilePath(packageName), \"utf-8\");\n const entry = JSON.parse(raw) as CacheEntry;\n const age = (Date.now() - new Date(entry.fetchedAt).getTime()) / 1000;\n if (age > (entry.ttl ?? ttlSeconds)) return null;\n const data = entry.data;\n return {\n ...data,\n sections: data.sections ?? [\"releases\", \"vitals\", \"reviews\"],\n cached: true,\n };\n } catch {\n return null;\n }\n}\n\nexport async function saveStatusCache(\n packageName: string,\n data: AppStatus,\n ttlSeconds = DEFAULT_TTL_SECONDS,\n): Promise<void> {\n try {\n const dir = getCacheDir();\n await mkdir(dir, { recursive: true });\n const entry: CacheEntry = { fetchedAt: data.fetchedAt, ttl: ttlSeconds, data };\n await writeFile(cacheFilePath(packageName), JSON.stringify(entry, null, 2), {\n encoding: \"utf-8\",\n mode: 0o600,\n });\n } catch {\n // Cache write failures must never break the command\n }\n}\n\n// ---------------------------------------------------------------------------\n// Vitals helpers\n// ---------------------------------------------------------------------------\n\nconst METRIC_SET_METRICS: Partial<Record<VitalsMetricSet, string[]>> = {\n crashRateMetricSet: [\"crashRate\", \"userPerceivedCrashRate\", \"distinctUsers\"],\n anrRateMetricSet: [\"anrRate\", \"userPerceivedAnrRate\", \"distinctUsers\"],\n slowStartRateMetricSet: [\"slowStartRate\", \"distinctUsers\"],\n slowRenderingRateMetricSet: [\"slowRenderingRate\", \"distinctUsers\"],\n};\n\nconst DEFAULT_THRESHOLDS = {\n crashRate: 0.02,\n anrRate: 0.01,\n slowStartRate: 0.05,\n slowRenderingRate: 0.1,\n};\n\nconst WARN_MARGIN = 0.2; // within 20% of threshold → warn\n\nfunction toApiDate(d: Date): { year: number; month: number; day: number } {\n return { year: d.getUTCFullYear(), month: d.getUTCMonth() + 1, day: d.getUTCDate() };\n}\n\nasync function queryVitalForStatus(\n reporting: ReportingApiClient,\n packageName: string,\n metricSet: VitalsMetricSet,\n days: number,\n offsetDays = 0,\n): Promise<number | undefined> {\n const DAY_MS = 24 * 60 * 60 * 1000;\n const baseMs = Date.now() - 2 * DAY_MS - offsetDays * DAY_MS;\n const end = new Date(baseMs);\n const start = new Date(baseMs - days * DAY_MS);\n const metrics = METRIC_SET_METRICS[metricSet] ?? [\"distinctUsers\"];\n\n const query: MetricSetQuery = {\n metrics,\n timelineSpec: {\n aggregationPeriod: \"DAILY\",\n startTime: toApiDate(start),\n endTime: toApiDate(end),\n },\n };\n\n const result = await reporting.queryMetricSet(packageName, metricSet, query);\n if (!result.rows || result.rows.length === 0) return undefined;\n\n const values = result.rows\n .map((row) => {\n const firstKey = Object.keys(row.metrics)[0];\n return firstKey ? Number(row.metrics[firstKey]?.decimalValue?.value) : NaN;\n })\n .filter((v) => !isNaN(v));\n\n if (values.length === 0) return undefined;\n return values.reduce((a, b) => a + b, 0) / values.length;\n}\n\ninterface VitalWithTrend {\n current: number | undefined;\n previous: number | undefined;\n trend: \"up\" | \"down\" | \"flat\" | null;\n}\n\nasync function queryVitalWithTrend(\n reporting: ReportingApiClient,\n packageName: string,\n metricSet: VitalsMetricSet,\n days: number,\n): Promise<VitalWithTrend> {\n const [current, previous] = await Promise.all([\n queryVitalForStatus(reporting, packageName, metricSet, days, 0),\n queryVitalForStatus(reporting, packageName, metricSet, days, days),\n ]);\n\n let trend: \"up\" | \"down\" | \"flat\" | null = null;\n if (current !== undefined && previous !== undefined) {\n if (current > previous) trend = \"up\";\n else if (current < previous) trend = \"down\";\n else trend = \"flat\";\n }\n\n return { current, previous, trend };\n}\n\nconst SKIPPED_VITAL: VitalWithTrend = { current: undefined, previous: undefined, trend: null };\n\nfunction toVitalMetric(\n value: number | undefined,\n threshold: number,\n previousValue?: number | undefined,\n trend?: \"up\" | \"down\" | \"flat\" | null,\n): StatusVitalMetric {\n const base: StatusVitalMetric =\n previousValue !== undefined\n ? { value, threshold, status: \"unknown\", previousValue, trend: trend ?? null }\n : { value, threshold, status: \"unknown\" };\n\n if (value === undefined) return { ...base, status: \"unknown\" };\n if (value > threshold) return { ...base, status: \"breach\" };\n if (value > threshold * (1 - WARN_MARGIN)) return { ...base, status: \"warn\" };\n return { ...base, status: \"ok\" };\n}\n\n// ---------------------------------------------------------------------------\n// Reviews helpers\n// ---------------------------------------------------------------------------\n\nfunction computeReviewSentiment(\n reviews: Awaited<ReturnType<typeof listReviews>>,\n windowDays: number,\n): StatusReviews {\n const now = Date.now();\n const DAY_MS = 24 * 60 * 60 * 1000;\n const windowMs = windowDays * DAY_MS;\n const prevWindowStart = now - 2 * windowMs;\n const curWindowStart = now - windowMs;\n\n const current = reviews.filter((r) => {\n const uc = r.comments?.[0]?.userComment;\n if (!uc) return false;\n const ts = Number(uc.lastModified.seconds) * 1000;\n return ts >= curWindowStart;\n });\n\n const previous = reviews.filter((r) => {\n const uc = r.comments?.[0]?.userComment;\n if (!uc) return false;\n const ts = Number(uc.lastModified.seconds) * 1000;\n return ts >= prevWindowStart && ts < curWindowStart;\n });\n\n const avgRating = (items: typeof reviews): number | undefined => {\n const ratings = items\n .map((r) => r.comments?.[0]?.userComment?.starRating)\n .filter((v): v is number => v !== undefined && v > 0);\n if (ratings.length === 0) return undefined;\n return Math.round((ratings.reduce((a, b) => a + b, 0) / ratings.length) * 10) / 10;\n };\n\n const positiveCount = current.filter(\n (r) => (r.comments?.[0]?.userComment?.starRating ?? 0) >= 4,\n ).length;\n\n const positivePercent =\n current.length > 0 ? Math.round((positiveCount / current.length) * 100) : undefined;\n\n return {\n windowDays,\n averageRating: avgRating(current),\n previousAverageRating: avgRating(previous),\n totalNew: current.length,\n positivePercent,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Main orchestrator\n// ---------------------------------------------------------------------------\n\nexport async function getAppStatus(\n client: PlayApiClient,\n reporting: ReportingApiClient,\n packageName: string,\n options: GetAppStatusOptions = {},\n): Promise<AppStatus> {\n const days = options.days ?? 7;\n const reviewDays = options.reviewDays ?? 30;\n const sections = new Set(options.sections ?? [\"releases\", \"vitals\", \"reviews\"]);\n const thresholds = {\n crashRate: options.vitalThresholds?.crashRate ?? DEFAULT_THRESHOLDS.crashRate,\n anrRate: options.vitalThresholds?.anrRate ?? DEFAULT_THRESHOLDS.anrRate,\n slowStartRate: options.vitalThresholds?.slowStartRate ?? DEFAULT_THRESHOLDS.slowStartRate,\n slowRenderingRate:\n options.vitalThresholds?.slowRenderingRate ?? DEFAULT_THRESHOLDS.slowRenderingRate,\n };\n\n const [\n releasesResult,\n crashesResult,\n anrResult,\n slowStartResult,\n slowRenderResult,\n reviewsResult,\n ] = await Promise.allSettled([\n sections.has(\"releases\") ? getReleasesStatus(client, packageName) : Promise.resolve([]),\n sections.has(\"vitals\")\n ? queryVitalWithTrend(reporting, packageName, \"crashRateMetricSet\", days)\n : Promise.resolve(SKIPPED_VITAL),\n sections.has(\"vitals\")\n ? queryVitalWithTrend(reporting, packageName, \"anrRateMetricSet\", days)\n : Promise.resolve(SKIPPED_VITAL),\n sections.has(\"vitals\")\n ? queryVitalWithTrend(reporting, packageName, \"slowStartRateMetricSet\", days)\n : Promise.resolve(SKIPPED_VITAL),\n sections.has(\"vitals\")\n ? queryVitalWithTrend(reporting, packageName, \"slowRenderingRateMetricSet\", days)\n : Promise.resolve(SKIPPED_VITAL),\n sections.has(\"reviews\")\n ? listReviews(client, packageName, { maxResults: 500 })\n : Promise.resolve([]),\n ]);\n\n const rawReleases = releasesResult.status === \"fulfilled\" ? releasesResult.value : [];\n const releases: StatusRelease[] = rawReleases.map((r) => ({\n track: r.track,\n versionCode: r.versionCodes[r.versionCodes.length - 1] ?? \"—\",\n status: r.status,\n userFraction: r.userFraction ?? null,\n }));\n\n const crashes = crashesResult.status === \"fulfilled\" ? crashesResult.value : SKIPPED_VITAL;\n const anr = anrResult.status === \"fulfilled\" ? anrResult.value : SKIPPED_VITAL;\n const slowStart = slowStartResult.status === \"fulfilled\" ? slowStartResult.value : SKIPPED_VITAL;\n const slowRender =\n slowRenderResult.status === \"fulfilled\" ? slowRenderResult.value : SKIPPED_VITAL;\n\n const rawReviews = reviewsResult.status === \"fulfilled\" ? reviewsResult.value : [];\n const reviews = computeReviewSentiment(rawReviews, reviewDays);\n\n return {\n packageName,\n fetchedAt: new Date().toISOString(),\n cached: false,\n sections: [...sections],\n releases,\n vitals: {\n windowDays: days,\n crashes: toVitalMetric(\n crashes.current,\n thresholds.crashRate,\n crashes.previous,\n crashes.trend,\n ),\n anr: toVitalMetric(anr.current, thresholds.anrRate, anr.previous, anr.trend),\n slowStarts: toVitalMetric(\n slowStart.current,\n thresholds.slowStartRate,\n slowStart.previous,\n slowStart.trend,\n ),\n slowRender: toVitalMetric(\n slowRender.current,\n thresholds.slowRenderingRate,\n slowRender.previous,\n slowRender.trend,\n ),\n },\n reviews,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Table formatter\n// ---------------------------------------------------------------------------\n\nfunction vitalIndicator(metric: StatusVitalMetric): string {\n if (metric.status === \"unknown\") return \"—\";\n if (metric.status === \"breach\") return \"✗\";\n if (metric.status === \"warn\") return \"⚠\";\n return \"✓\";\n}\n\n// For all vital metrics (crash rate, ANR, slow starts, slow render) lower is better:\n// trend \"up\" (increasing) is bad → ↑, trend \"down\" (decreasing) is good → ↓\nfunction vitalTrendArrow(metric: StatusVitalMetric): string {\n if (!metric.trend || metric.trend === \"flat\") return \"\";\n return metric.trend === \"up\" ? \" ↑\" : \" ↓\";\n}\n\nfunction formatVitalValue(metric: StatusVitalMetric): string {\n if (metric.value === undefined) return \"—\";\n return `${(metric.value * 100).toFixed(2)}%`;\n}\n\nfunction formatFraction(fraction: number | null): string {\n if (fraction === null) return \"—\";\n return `${Math.round(fraction * 100)}%`;\n}\n\nfunction formatRating(rating: number | undefined): string {\n if (rating === undefined) return \"—\";\n return `★ ${rating.toFixed(1)}`;\n}\n\nfunction formatTrend(current: number | undefined, previous: number | undefined): string {\n if (current === undefined || previous === undefined) return \"\";\n if (current > previous) return ` ↑ from ${previous.toFixed(1)}`;\n if (current < previous) return ` ↓ from ${previous.toFixed(1)}`;\n return \"\";\n}\n\nexport function relativeTime(isoString: string): string {\n const diffMs = Date.now() - new Date(isoString).getTime();\n const diffMin = Math.floor(diffMs / 60000);\n if (diffMin < 1) return \"just now\";\n if (diffMin < 60) return `${diffMin} min ago`;\n const diffHr = Math.floor(diffMin / 60);\n if (diffHr < 24) return `${diffHr}h ago`;\n return `${Math.floor(diffHr / 24)}d ago`;\n}\n\nfunction allVitalsUnknown(vitals: AppStatus[\"vitals\"]): boolean {\n return (\n vitals.crashes.status === \"unknown\" &&\n vitals.anr.status === \"unknown\" &&\n vitals.slowStarts.status === \"unknown\" &&\n vitals.slowRender.status === \"unknown\"\n );\n}\n\nexport function formatStatusTable(status: AppStatus): string {\n const lines: string[] = [];\n const sectionSet = new Set(status.sections);\n const cachedLabel = status.cached\n ? ` (cached ${relativeTime(status.fetchedAt)})`\n : ` (fetched ${relativeTime(status.fetchedAt)})`;\n\n lines.push(`App: ${status.packageName}${cachedLabel}`);\n\n // Releases\n if (sectionSet.has(\"releases\")) {\n lines.push(\"\");\n lines.push(\"RELEASES\");\n if (status.releases.length === 0) {\n lines.push(\" No releases found.\");\n } else {\n const trackW = Math.max(10, ...status.releases.map((r) => r.track.length));\n const versionW = Math.max(7, ...status.releases.map((r) => r.versionCode.length));\n const statusW = Math.max(8, ...status.releases.map((r) => r.status.length));\n for (const r of status.releases) {\n lines.push(\n ` ${r.track.padEnd(trackW)} ${r.versionCode.padEnd(versionW)} ${r.status.padEnd(statusW)} ${formatFraction(r.userFraction)}`,\n );\n }\n }\n }\n\n // Vitals\n if (sectionSet.has(\"vitals\")) {\n lines.push(\"\");\n lines.push(`VITALS (last ${status.vitals.windowDays} days)`);\n if (allVitalsUnknown(status.vitals)) {\n lines.push(\" No vitals data available for this period.\");\n } else {\n const { crashes, anr, slowStarts, slowRender } = status.vitals;\n const crashVal = `${formatVitalValue(crashes)}${vitalTrendArrow(crashes)}`;\n const anrVal = `${formatVitalValue(anr)}${vitalTrendArrow(anr)}`;\n const slowStartVal = `${formatVitalValue(slowStarts)}${vitalTrendArrow(slowStarts)}`;\n const slowRenderVal = `${formatVitalValue(slowRender)}${vitalTrendArrow(slowRender)}`;\n lines.push(\n ` crashes ${crashVal.padEnd(10)} ${vitalIndicator(crashes)} ` +\n `anr ${anrVal.padEnd(10)} ${vitalIndicator(anr)}`,\n );\n lines.push(\n ` slow starts ${slowStartVal.padEnd(10)} ${vitalIndicator(slowStarts)} ` +\n `slow render ${slowRenderVal.padEnd(10)} ${vitalIndicator(slowRender)}`,\n );\n }\n }\n\n // Reviews\n if (sectionSet.has(\"reviews\")) {\n lines.push(\"\");\n lines.push(`REVIEWS (last ${status.reviews.windowDays} days)`);\n const { averageRating, previousAverageRating, totalNew, positivePercent } = status.reviews;\n if (totalNew === 0 && averageRating === undefined) {\n lines.push(\" No reviews in this period.\");\n } else {\n const trend = formatTrend(averageRating, previousAverageRating);\n const positiveStr = positivePercent !== undefined ? ` ${positivePercent}% positive` : \"\";\n lines.push(` ${formatRating(averageRating)} ${totalNew} new${positiveStr}${trend}`);\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// Summary formatter (one-liner for --format summary)\n// ---------------------------------------------------------------------------\n\nexport function formatStatusSummary(status: AppStatus): string {\n const parts: string[] = [status.packageName];\n\n // Latest non-draft release\n const latestRelease = status.releases.find((r) => r.status !== \"draft\") ?? status.releases[0];\n if (latestRelease) {\n parts.push(`v${latestRelease.versionCode} ${latestRelease.track}`);\n }\n\n // Vitals (crashes + ANR only for brevity)\n const { crashes, anr } = status.vitals;\n const allVitalsUnknown = crashes.status === \"unknown\" && anr.status === \"unknown\";\n if (allVitalsUnknown) {\n parts.push(\"no vitals\");\n } else {\n if (crashes.status !== \"unknown\") {\n const arrow = crashes.trend === \"up\" ? \" ↑\" : crashes.trend === \"down\" ? \" ↓\" : \"\";\n parts.push(`crashes ${formatVitalValue(crashes)}${arrow} ${vitalIndicator(crashes)}`);\n }\n if (anr.status !== \"unknown\") {\n const arrow = anr.trend === \"up\" ? \" ↑\" : anr.trend === \"down\" ? \" ↓\" : \"\";\n parts.push(`ANR ${formatVitalValue(anr)}${arrow} ${vitalIndicator(anr)}`);\n }\n }\n\n // Reviews\n const { averageRating, totalNew } = status.reviews;\n if (averageRating !== undefined) {\n parts.push(`avg ${averageRating.toFixed(1)}★`);\n if (totalNew > 0) parts.push(`${totalNew} reviews`);\n } else {\n parts.push(\"no reviews\");\n }\n\n return parts.join(\" · \") + (statusHasBreach(status) ? \" [ALERT]\" : \"\");\n}\n\n// ---------------------------------------------------------------------------\n// Diff (--since-last)\n// ---------------------------------------------------------------------------\n\nfunction latestProductionVersion(releases: StatusRelease[]): string | null {\n const prod = releases.find((r) => r.track === \"production\");\n if (prod) return prod.versionCode;\n // Fallback: first non-draft release, then first release\n const nonDraft = releases.find((r) => r.status !== \"draft\");\n return nonDraft?.versionCode ?? releases[0]?.versionCode ?? null;\n}\n\nexport function computeStatusDiff(prev: AppStatus, curr: AppStatus): StatusDiff {\n const prevVersion = latestProductionVersion(prev.releases);\n const currVersion = latestProductionVersion(curr.releases);\n const prevCrash = prev.vitals.crashes.value ?? null;\n const currCrash = curr.vitals.crashes.value ?? null;\n const prevAnr = prev.vitals.anr.value ?? null;\n const currAnr = curr.vitals.anr.value ?? null;\n const prevRating = prev.reviews.averageRating ?? null;\n const currRating = curr.reviews.averageRating ?? null;\n\n return {\n versionCode: { from: prevVersion, to: currVersion },\n crashRate: {\n from: prevCrash,\n to: currCrash,\n delta: currCrash !== null && prevCrash !== null ? currCrash - prevCrash : null,\n },\n anrRate: {\n from: prevAnr,\n to: currAnr,\n delta: currAnr !== null && prevAnr !== null ? currAnr - prevAnr : null,\n },\n reviewCount: { from: prev.reviews.totalNew, to: curr.reviews.totalNew },\n averageRating: {\n from: prevRating,\n to: currRating,\n delta:\n currRating !== null && prevRating !== null\n ? Math.round((currRating - prevRating) * 10) / 10\n : null,\n },\n };\n}\n\nexport function formatStatusDiff(diff: StatusDiff, since: string): string {\n const lines: string[] = [`Changes since ${since}:`];\n\n if (diff.versionCode.from !== diff.versionCode.to) {\n lines.push(` Version: ${diff.versionCode.from ?? \"—\"} → ${diff.versionCode.to ?? \"—\"}`);\n }\n\n const fmtRate = (v: number | null): string => (v !== null ? `${(v * 100).toFixed(2)}%` : \"—\");\n\n const fmtDelta = (d: number | null, lowerIsBetter = true): string => {\n if (d === null || Math.abs(d) < 0.0001) return \"no change\";\n const sign = d > 0 ? \"+\" : \"\";\n const good = lowerIsBetter ? d < 0 : d > 0;\n return `${sign}${(d * 100).toFixed(2)}% ${good ? \"✓\" : \"✗\"}`;\n };\n\n lines.push(\n ` Crash rate: ${fmtRate(diff.crashRate.from)} → ${fmtRate(diff.crashRate.to)} (${fmtDelta(diff.crashRate.delta)})`,\n );\n lines.push(\n ` ANR rate: ${fmtRate(diff.anrRate.from)} → ${fmtRate(diff.anrRate.to)} (${fmtDelta(diff.anrRate.delta)})`,\n );\n\n const ratingDelta = diff.averageRating.delta;\n const prevR = diff.averageRating.from !== null ? `${diff.averageRating.from.toFixed(1)}★` : \"—\";\n const currR = diff.averageRating.to !== null ? `${diff.averageRating.to.toFixed(1)}★` : \"—\";\n const ratingStr =\n ratingDelta === null || Math.abs(ratingDelta) < 0.05\n ? \"no change\"\n : `${ratingDelta > 0 ? \"+\" : \"\"}${ratingDelta.toFixed(1)} ${ratingDelta > 0 ? \"✓\" : \"✗\"}`;\n lines.push(` Reviews: ${prevR} → ${currR} (${ratingStr})`);\n\n return lines.join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// Watch loop (--watch N)\n// ---------------------------------------------------------------------------\n\nexport async function runWatchLoop(opts: WatchOptions): Promise<void> {\n if (opts.intervalSeconds < 10) {\n throw new GpcError(\n \"--watch interval must be at least 10 seconds\",\n \"STATUS_USAGE_ERROR\",\n 2,\n \"Use --watch 10 or higher.\",\n );\n }\n\n let running = true;\n\n const cleanup = () => {\n running = false;\n };\n process.on(\"SIGINT\", cleanup);\n process.on(\"SIGTERM\", cleanup);\n\n while (running) {\n process.stdout.write(\"\\x1b[2J\\x1b[H\"); // clear terminal\n const fetchedAt = Date.now();\n\n try {\n const status = await opts.fetch();\n await opts.save(status);\n console.log(opts.render(status));\n } catch (err) {\n console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n // Sleep in 1s ticks so SIGINT is responsive, update footer with elapsed time\n for (let i = 0; i < opts.intervalSeconds && running; i++) {\n const elapsed = Math.round((Date.now() - fetchedAt) / 1000);\n const remaining = opts.intervalSeconds - i;\n process.stdout.write(\n `\\r[gpc status] Fetched ${elapsed}s ago · refreshing in ${remaining}s (Ctrl+C to stop)\\x1b[K`,\n );\n await new Promise<void>((r) => setTimeout(r, 1000));\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Notifications (--notify)\n// ---------------------------------------------------------------------------\n\nfunction breachStateFilePath(packageName: string): string {\n return join(getCacheDir(), `breach-state-${packageName}.json`);\n}\n\n/** Returns true if breach state changed (breach started or cleared). */\nexport async function trackBreachState(\n packageName: string,\n isBreaching: boolean,\n): Promise<boolean> {\n const filePath = breachStateFilePath(packageName);\n let prevBreaching = false;\n\n try {\n const raw = await readFile(filePath, \"utf-8\");\n prevBreaching = (JSON.parse(raw) as { breaching: boolean }).breaching;\n } catch {\n // No prior state — first run\n }\n\n if (prevBreaching !== isBreaching) {\n try {\n await mkdir(getCacheDir(), { recursive: true });\n await writeFile(\n filePath,\n JSON.stringify({ breaching: isBreaching, since: new Date().toISOString() }, null, 2),\n { encoding: \"utf-8\", mode: 0o600 },\n );\n } catch {\n // State write failure is non-fatal\n }\n return true;\n }\n return false;\n}\n\nexport function sendNotification(title: string, body: string): void {\n if (process.env[\"CI\"]) return; // Skip in CI environments\n\n try {\n const p = process.platform;\n if (p === \"darwin\") {\n // execFile avoids shell parsing; AppleScript string uses JSON.stringify for safe quoting\n execFile(\"osascript\", [\n \"-e\",\n `display notification ${JSON.stringify(body)} with title ${JSON.stringify(title)}`,\n ]);\n } else if (p === \"linux\") {\n // Pass title and body as separate argv elements — no shell, no escaping needed\n execFile(\"notify-send\", [title, body]);\n } else if (p === \"win32\") {\n // Escape single quotes for PowerShell literal strings; execFile skips shell parsing\n // so no double-quote injection risk from the outer command string\n const psEscape = (s: string) =>\n s\n .replace(/'/g, \"''\") // PS single-quote escape\n .replace(/[\\r\\n]/g, \" \"); // strip newlines that would break the -Command string\n execFile(\"powershell\", [\n \"-NoProfile\",\n \"-NonInteractive\",\n \"-Command\",\n `Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.MessageBox]::Show('${psEscape(body)}', '${psEscape(title)}')`,\n ]);\n }\n } catch {\n // Notification failures are non-fatal\n }\n}\n\n// ---------------------------------------------------------------------------\n// Status indicator for exit code (mirrors gpc vitals behaviour)\n// ---------------------------------------------------------------------------\n\nexport function statusHasBreach(status: AppStatus): boolean {\n return (\n status.vitals.crashes.status === \"breach\" ||\n status.vitals.anr.status === \"breach\" ||\n status.vitals.slowStarts.status === \"breach\" ||\n status.vitals.slowRender.status === \"breach\"\n );\n}\n","const GITHUB_RELEASES_URL =\n \"https://api.github.com/repos/yasserstudio/gpc/releases\";\n\nconst DOCS_CHANGELOG_URL =\n \"https://yasserstudio.github.io/gpc/reference/changelog\";\n\nexport interface ChangelogEntry {\n version: string;\n title: string;\n date: string;\n body: string;\n url: string;\n}\n\nexport interface FetchChangelogOptions {\n limit?: number;\n version?: string;\n}\n\n/**\n * Fetch release history from GitHub Releases API.\n * Public endpoint — no auth required (60 req/hour rate limit).\n */\nexport async function fetchChangelog(\n options?: FetchChangelogOptions,\n): Promise<ChangelogEntry[]> {\n const limit = options?.limit ?? 5;\n\n const url = options?.version\n ? `${GITHUB_RELEASES_URL}/tags/${options.version.startsWith(\"v\") ? options.version : `v${options.version}`}`\n : `${GITHUB_RELEASES_URL}?per_page=${Math.min(limit, 100)}`;\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 10_000);\n\n let response: Response;\n try {\n response = await fetch(url, {\n headers: {\n Accept: \"application/vnd.github+json\",\n \"User-Agent\": \"gpc-cli\",\n },\n signal: controller.signal,\n });\n } catch {\n throw new Error(\n `Could not fetch changelog. View online: ${DOCS_CHANGELOG_URL}`,\n );\n } finally {\n clearTimeout(timer);\n }\n\n if (!response.ok) {\n if (response.status === 404 && options?.version) {\n throw new Error(\n `Version ${options.version} not found. Run: gpc changelog --limit 10`,\n );\n }\n throw new Error(\n `GitHub API returned ${response.status}. View online: ${DOCS_CHANGELOG_URL}`,\n );\n }\n\n const data = await response.json();\n const releases: Array<{\n tag_name: string;\n name: string;\n published_at: string;\n body: string;\n html_url: string;\n }> = Array.isArray(data) ? data : [data];\n\n return releases\n .filter((r) => r.tag_name.startsWith(\"v\"))\n .map((r) => ({\n version: r.tag_name,\n title: r.name || r.tag_name,\n date: r.published_at ? r.published_at.split(\"T\")[0]! : \"unknown\",\n body: r.body || \"No release notes.\",\n url: r.html_url,\n }));\n}\n\n/**\n * Format a changelog entry as readable terminal text.\n * Strips markdown formatting for clean terminal output.\n */\nexport function formatChangelogEntry(entry: ChangelogEntry): string {\n const lines: string[] = [];\n lines.push(`${entry.version} — ${entry.title}`);\n lines.push(`Released: ${entry.date}`);\n lines.push(\"\");\n\n // Strip markdown formatting for terminal display\n const body = entry.body\n .replace(/^### /gm, \"\")\n .replace(/^## /gm, \"\")\n .replace(/^# /gm, \"\")\n .replace(/\\*\\*(.*?)\\*\\*/g, \"$1\")\n .replace(/`([^`]+)`/g, \"$1\")\n .replace(/\\[([^\\]]+)\\]\\([^)]+\\)/g, \"$1\")\n .trim();\n\n lines.push(body);\n lines.push(\"\");\n lines.push(`Full notes: ${entry.url}`);\n\n return lines.join(\"\\n\");\n}\n","import type { PlayApiClient } from \"@gpc-cli/api\";\nimport { GpcError } from \"../errors.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface RtdnConfig {\n topicName?: string;\n enabled?: boolean;\n}\n\nexport interface RtdnStatus {\n topicName: string | null;\n enabled: boolean;\n}\n\nexport interface DecodedNotification {\n version: string;\n packageName: string;\n eventTimeMillis: string;\n subscriptionNotification?: {\n version: string;\n notificationType: number;\n purchaseToken: string;\n subscriptionId: string;\n };\n oneTimeProductNotification?: {\n version: string;\n notificationType: number;\n purchaseToken: string;\n sku: string;\n };\n voidedPurchaseNotification?: {\n purchaseToken: string;\n orderId: string;\n productType: number;\n refundType?: number;\n };\n testNotification?: {\n version: string;\n };\n}\n\n// RTDN notification type names\nconst SUBSCRIPTION_NOTIFICATION_TYPES: Record<number, string> = {\n 1: \"SUBSCRIPTION_RECOVERED\",\n 2: \"SUBSCRIPTION_RENEWED\",\n 3: \"SUBSCRIPTION_CANCELED\",\n 4: \"SUBSCRIPTION_PURCHASED\",\n 5: \"SUBSCRIPTION_ON_HOLD\",\n 6: \"SUBSCRIPTION_IN_GRACE_PERIOD\",\n 7: \"SUBSCRIPTION_RESTARTED\",\n 8: \"SUBSCRIPTION_PRICE_CHANGE_CONFIRMED\",\n 9: \"SUBSCRIPTION_DEFERRED\",\n 10: \"SUBSCRIPTION_PAUSED\",\n 11: \"SUBSCRIPTION_PAUSE_SCHEDULE_CHANGED\",\n 12: \"SUBSCRIPTION_REVOKED\",\n 13: \"SUBSCRIPTION_EXPIRED\",\n 20: \"SUBSCRIPTION_PENDING_PURCHASE_CANCELED\",\n};\n\nconst OTP_NOTIFICATION_TYPES: Record<number, string> = {\n 1: \"ONE_TIME_PRODUCT_PURCHASED\",\n 2: \"ONE_TIME_PRODUCT_CANCELED\",\n};\n\n// ---------------------------------------------------------------------------\n// Functions\n// ---------------------------------------------------------------------------\n\n/**\n * Get RTDN status by reading the app's notification topic configuration.\n * Uses the monetization settings endpoint if available, otherwise returns defaults.\n */\nexport async function getRtdnStatus(\n client: PlayApiClient,\n packageName: string,\n): Promise<RtdnStatus> {\n try {\n // The RTDN topic is configured via the Developer API notification settings\n // This is typically set via the Play Console or the API's appInformation endpoint\n const edit = await client.edits.insert(packageName);\n try {\n const details = await client.details.get(packageName, edit.id);\n // App details doesn't directly expose RTDN topic — return basic info\n return {\n topicName: null,\n enabled: false,\n };\n } finally {\n await client.edits.delete(packageName, edit.id).catch(() => {});\n }\n } catch {\n return { topicName: null, enabled: false };\n }\n}\n\n/**\n * Decode a base64-encoded RTDN notification payload.\n * Pub/Sub messages from Google Play are base64-encoded JSON.\n */\nexport function decodeNotification(base64Payload: string): DecodedNotification {\n try {\n const json = Buffer.from(base64Payload, \"base64\").toString(\"utf-8\");\n return JSON.parse(json) as DecodedNotification;\n } catch {\n throw new GpcError(\n \"Failed to decode notification payload. Expected base64-encoded JSON.\",\n \"RTDN_DECODE_ERROR\",\n 1,\n \"Ensure the payload is a valid base64-encoded Pub/Sub message from Google Play.\",\n );\n }\n}\n\n/**\n * Format a decoded notification into a human-readable summary.\n */\nexport function formatNotification(notification: DecodedNotification): Record<string, unknown> {\n const base: Record<string, unknown> = {\n packageName: notification.packageName,\n eventTime: notification.eventTimeMillis\n ? new Date(Number(notification.eventTimeMillis)).toISOString()\n : \"-\",\n version: notification.version,\n };\n\n if (notification.subscriptionNotification) {\n const n = notification.subscriptionNotification;\n return {\n ...base,\n type: \"subscription\",\n event: SUBSCRIPTION_NOTIFICATION_TYPES[n.notificationType] || `UNKNOWN(${n.notificationType})`,\n subscriptionId: n.subscriptionId,\n purchaseToken: n.purchaseToken.slice(0, 16) + \"...\",\n };\n }\n\n if (notification.oneTimeProductNotification) {\n const n = notification.oneTimeProductNotification;\n return {\n ...base,\n type: \"one-time-product\",\n event: OTP_NOTIFICATION_TYPES[n.notificationType] || `UNKNOWN(${n.notificationType})`,\n sku: n.sku,\n purchaseToken: n.purchaseToken.slice(0, 16) + \"...\",\n };\n }\n\n if (notification.voidedPurchaseNotification) {\n const n = notification.voidedPurchaseNotification;\n return {\n ...base,\n type: \"voided-purchase\",\n event: \"VOIDED_PURCHASE\",\n orderId: n.orderId,\n purchaseToken: n.purchaseToken.slice(0, 16) + \"...\",\n };\n }\n\n if (notification.testNotification) {\n return { ...base, type: \"test\", event: \"TEST_NOTIFICATION\" };\n }\n\n return { ...base, type: \"unknown\" };\n}\n"],"mappings":"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","names":["process","resolve","stat","extname","edit","stat","extname","stat","extname","formatSize","stat","SAFE_LANG","i","j","mkdir","writeFile","join","readdir","readFile","writeFile","mkdir","join","readdir","readFile","stat","extname","join","readdir","extname","join","stat","readFile","stat","formatSize","stat","upload","analyzeReviews","paginateAll","paginateAll","toApiDate","readdir","readFile","join","paginateAll","paginateAll","readdir","readFile","join","paginateAll","dim","paginateAll","paginateAll","readFile","readFile","readFile","writeFile","writeFile","readFile","process","mkdir","readFile","writeFile","join","parseDuration","parseDuration","mkdir","readFile","writeFile","join","join","readFile","writeFile","mkdir","writeFile","stat","join","exists","readFile","readFile","resolve","readdir","stat","readFile","join","FILE_MAP","readdir","join","stat","readFile","readFile","readdir","stat","join","extname","readFile","readFile","SCAN_EXTENSIONS","readFile","readFile","SCAN_EXTENSIONS","readFile","mkdir","writeFile","join","extname","extname","writeFile","writeFile","readFile","stat","detectCategory","detectFileType","mkdir","readFile","writeFile","execFile","join","getCacheDir","join","getCacheDir","readFile","mkdir","writeFile","METRIC_SET_METRICS","allVitalsUnknown","execFile"]}
|