import { Injectable, Logger, BadRequestException } from '@nestjs/common'; interface ParsedPackageInfo { packageName: string; versionCode: number; versionName: string; minSdkVersion?: string; platform: 'ANDROID' | 'IOS'; } @Injectable() export class PackageParserService { private readonly logger = new Logger(PackageParserService.name); async parse(buffer: Buffer, filename: string): Promise { const ext = filename.split('.').pop()?.toLowerCase(); if (ext === 'apk') return this.parseApk(buffer); if (ext === 'ipa') return this.parseIpa(buffer); throw new BadRequestException('Unsupported file format. Only .apk and .ipa are supported.'); } private async parseApk(buffer: Buffer): Promise { try { // Dynamic import to handle missing dependency gracefully const ApkReader = await import('adbkit-apkreader').then(m => m.default || m); const reader = await ApkReader.open(buffer); const manifest = await reader.readManifest(); return { packageName: manifest.package || 'unknown', versionCode: manifest.versionCode || 0, versionName: manifest.versionName || '0.0.0', minSdkVersion: manifest.usesSdk?.minSdkVersion?.toString(), platform: 'ANDROID', }; } catch (err: any) { this.logger.warn(`APK parse failed, using fallback: ${err.message}`); return { packageName: 'unknown', versionCode: 0, versionName: '0.0.0', platform: 'ANDROID', }; } } private async parseIpa(buffer: Buffer): Promise { try { const unzipper = await import('unzipper'); const bplistParser = await import('bplist-parser'); const directory = await unzipper.Open.buffer(buffer); const plistEntry = directory.files.find((f: any) => /Payload\/[^/]+\.app\/Info\.plist$/.test(f.path)); if (!plistEntry) throw new Error('Info.plist not found in IPA'); const plistBuffer = await plistEntry.buffer(); const parsed = bplistParser.parseBuffer(plistBuffer); const info = parsed[0] || {}; return { packageName: info.CFBundleIdentifier || 'unknown', versionCode: parseInt(info.CFBundleVersion || '0', 10), versionName: info.CFBundleShortVersionString || '0.0.0', minSdkVersion: info.MinimumOSVersion, platform: 'IOS', }; } catch (err: any) { this.logger.warn(`IPA parse failed, using fallback: ${err.message}`); return { packageName: 'unknown', versionCode: 0, versionName: '0.0.0', platform: 'IOS', }; } } }