{"version":3,"sources":["../../src/xcode/platform.ts","../../src/xcode/keychain.ts","../../src/xcode/project.ts","../../src/xcode/upload.ts"],"names":["execFileAsync","promisify","execFile","join","writeFile","unlink"],"mappings":"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","file":"index.mjs","sourcesContent":["export function requireMacOS(feature: string): void {\n  if (process.platform !== \"darwin\") {\n    throw new Error(\n      `${feature} requires macOS. This operation uses Xcode command-line tools ` +\n      `which are not available on ${process.platform}.`\n    );\n  }\n}\n\nexport function isMacOS(): boolean {\n  return process.platform === \"darwin\";\n}\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { copyFile, mkdir, unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { randomBytes } from \"node:crypto\";\nimport { requireMacOS } from \"./platform.js\";\n\nconst execFileAsync = promisify(execFile);\n\nexport interface KeychainHandle {\n  path: string;\n  password: string;\n  cleanup(): Promise<void>;\n}\n\nexport async function createKeychain(options: {\n  name: string;\n  password?: string;\n}): Promise<KeychainHandle> {\n  requireMacOS(\"keychain\");\n\n  const password = options.password ?? randomBytes(16).toString(\"hex\");\n  const keychainName = `${options.name}.keychain-db`;\n  const keychainPath = join(homedir(), \"Library\", \"Keychains\", keychainName);\n\n  await execFileAsync(\"security\", [\"create-keychain\", \"-p\", password, keychainPath]);\n  await execFileAsync(\"security\", [\"set-keychain-settings\", \"-lut\", \"21600\", keychainPath]);\n  await execFileAsync(\"security\", [\"unlock-keychain\", \"-p\", password, keychainPath]);\n\n  // Add to search list\n  const { stdout: currentList } = await execFileAsync(\"security\", [\"list-keychains\", \"-d\", \"user\"]);\n  const keychains = currentList.split(\"\\n\").map((k) => k.trim().replace(/\"/g, \"\")).filter(Boolean);\n  const searchList = [keychainPath, ...keychains];\n  if (!searchList.includes(\"/Library/Keychains/System.keychain\")) {\n    searchList.push(\"/Library/Keychains/System.keychain\");\n  }\n  await execFileAsync(\"security\", [\"list-keychains\", \"-d\", \"user\", \"-s\", ...searchList]);\n\n  // Download and import WWDR cert\n  try {\n    const wwdrPath = \"/tmp/AppleWWDRCAG3.cer\";\n    await execFileAsync(\"curl\", [\"-sfo\", wwdrPath, \"https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer\"]);\n    await execFileAsync(\"security\", [\"import\", wwdrPath, \"-k\", keychainPath, \"-T\", \"/usr/bin/codesign\"]);\n  } catch {\n    // Non-fatal\n  }\n\n  return {\n    path: keychainPath,\n    password,\n    cleanup: () => cleanupKeychain({ path: keychainPath, password, cleanup: async () => {} }),\n  };\n}\n\nexport async function importCertificate(\n  keychainPath: string,\n  certPath: string,\n  password?: string\n): Promise<void> {\n  requireMacOS(\"keychain\");\n\n  const isCer = certPath.endsWith(\".cer\") || certPath.endsWith(\".pem\");\n  const args = isCer\n    ? [\"import\", certPath, \"-k\", keychainPath, \"-T\", \"/usr/bin/codesign\", \"-T\", \"/usr/bin/security\"]\n    : [\"import\", certPath, \"-k\", keychainPath, \"-P\", password ?? \"\", \"-T\", \"/usr/bin/codesign\", \"-T\", \"/usr/bin/security\"];\n\n  try {\n    await execFileAsync(\"security\", args);\n  } catch (err: unknown) {\n    const msg = err instanceof Error ? err.message : String(err);\n    if (!msg.includes(\"already exists\")) throw err;\n  }\n}\n\nexport async function installProfile(\n  profilePath: string,\n  uuid: string\n): Promise<string> {\n  const profilesDir = join(homedir(), \"Library\", \"MobileDevice\", \"Provisioning Profiles\");\n  await mkdir(profilesDir, { recursive: true });\n  const dest = join(profilesDir, `${uuid}.mobileprovision`);\n  await copyFile(profilePath, dest);\n  return dest;\n}\n\nexport async function cleanupKeychain(handle: KeychainHandle): Promise<void> {\n  try {\n    await execFileAsync(\"security\", [\"delete-keychain\", handle.path]);\n  } catch {\n    // Keychain may already be deleted\n  }\n}\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { requireMacOS } from \"./platform.js\";\n\nconst execFileAsync = promisify(execFile);\n\nexport async function updateSigningSettings(options: {\n  projectPath: string;\n  teamId: string;\n  bundleIdentifier: string;\n  codeSignIdentity: string;\n  targets?: string[];\n  profileName?: string;\n  profileUuid?: string;\n  automaticSigning?: boolean;\n}): Promise<void> {\n  const pbxprojPath = `${options.projectPath}/project.pbxproj`;\n  let content = await readFile(pbxprojPath, \"utf-8\");\n\n  const style = options.automaticSigning ? \"Automatic\" : \"Manual\";\n\n  // Replace build settings across the file\n  content = replaceBuildSetting(content, \"CODE_SIGN_STYLE\", style);\n  content = replaceBuildSetting(content, \"DEVELOPMENT_TEAM\", options.teamId);\n  content = replaceBuildSetting(content, \"CODE_SIGN_IDENTITY\", options.codeSignIdentity);\n\n  if (options.profileName) {\n    content = replaceBuildSetting(content, \"PROVISIONING_PROFILE_SPECIFIER\", options.profileName);\n  }\n  if (options.profileUuid) {\n    content = replaceBuildSetting(content, \"PROVISIONING_PROFILE\", options.profileUuid);\n  }\n\n  await writeFile(pbxprojPath, content);\n}\n\nexport async function setBuildNumber(\n  projectPath: string,\n  buildNumber: string\n): Promise<void> {\n  const pbxprojPath = `${projectPath}/project.pbxproj`;\n  let content = await readFile(pbxprojPath, \"utf-8\");\n  content = replaceBuildSetting(content, \"CURRENT_PROJECT_VERSION\", buildNumber);\n  await writeFile(pbxprojPath, content);\n}\n\nexport async function setVersionNumber(\n  projectPath: string,\n  version: string\n): Promise<void> {\n  const pbxprojPath = `${projectPath}/project.pbxproj`;\n  let content = await readFile(pbxprojPath, \"utf-8\");\n  content = replaceBuildSetting(content, \"MARKETING_VERSION\", version);\n  await writeFile(pbxprojPath, content);\n}\n\nexport async function readBuildSettings(options: {\n  projectPath?: string;\n  workspacePath?: string;\n  scheme: string;\n  configuration?: string;\n}): Promise<Record<string, string>> {\n  requireMacOS(\"readBuildSettings\");\n\n  const args = [\"-showBuildSettings\"];\n  if (options.workspacePath) args.push(\"-workspace\", options.workspacePath);\n  else if (options.projectPath) args.push(\"-project\", options.projectPath);\n  args.push(\"-scheme\", options.scheme);\n  if (options.configuration) args.push(\"-configuration\", options.configuration);\n\n  const { stdout } = await execFileAsync(\"xcodebuild\", args);\n  const settings: Record<string, string> = {};\n\n  for (const line of stdout.split(\"\\n\")) {\n    const match = line.match(/^\\s+(\\w+)\\s*=\\s*(.*)$/);\n    if (match) {\n      settings[match[1]] = match[2].trim();\n    }\n  }\n\n  return settings;\n}\n\nfunction replaceBuildSetting(content: string, key: string, value: string): string {\n  // Match: KEY = \"value\"; or KEY = value;\n  // Use negative lookbehind to avoid partial matches (e.g., PROVISIONING_PROFILE vs _SPECIFIER)\n  const regex = new RegExp(`(?<![A-Z_])(${key})\\\\s*=\\\\s*(\"[^\"]*\"|[^;]*);`, \"g\");\n  // Quote value if it contains non-alphanumeric chars or if the original was quoted\n  const needsQuotes = /[^A-Za-z0-9]/.test(value) || /\\s/.test(value);\n  const quoted = needsQuotes ? `\"${value}\"` : value;\n  return content.replace(regex, `$1 = ${quoted};`);\n}\n","import { spawn } from \"node:child_process\";\nimport { writeFile, unlink, mkdtemp } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport { requireMacOS } from \"./platform.js\";\n\nexport async function uploadWithAltool(options: {\n  filePath: string;\n  apiKeyId: string;\n  apiIssuerId: string;\n  apiPrivateKey?: string;\n  apiKeyPath?: string;\n  platform?: string;\n  onOutput?: (chunk: string) => void;\n}): Promise<{ success: boolean; output: string }> {\n  requireMacOS(\"altool upload\");\n\n  // Write temp .p8 if private key content provided\n  let keyDir: string | undefined;\n  if (options.apiPrivateKey && !options.apiKeyPath) {\n    keyDir = await mkdtemp(join(tmpdir(), \"fastnode-altool-\"));\n    const keyPath = join(keyDir, `AuthKey_${options.apiKeyId}.p8`);\n    await writeFile(keyPath, options.apiPrivateKey);\n  }\n\n  const args = [\n    \"altool\",\n    \"--upload-app\",\n    \"-f\", options.filePath,\n    \"-t\", options.platform ?? \"ios\",\n    \"--apiKey\", options.apiKeyId,\n    \"--apiIssuer\", options.apiIssuerId,\n  ];\n\n  const env = { ...process.env };\n  if (keyDir) {\n    env.API_PRIVATE_KEYS_DIR = keyDir;\n  }\n\n  return new Promise<{ success: boolean; output: string }>((resolve) => {\n    const child = spawn(\"xcrun\", args, {\n      env,\n      stdio: [\"ignore\", \"pipe\", \"pipe\"],\n    });\n\n    let output = \"\";\n\n    child.stdout.on(\"data\", (data: Buffer) => {\n      const chunk = data.toString();\n      output += chunk;\n      options.onOutput?.(chunk);\n    });\n\n    child.stderr.on(\"data\", (data: Buffer) => {\n      const chunk = data.toString();\n      output += chunk;\n      options.onOutput?.(chunk);\n    });\n\n    child.on(\"close\", async (code) => {\n      if (keyDir) {\n        const keyPath = join(keyDir, `AuthKey_${options.apiKeyId}.p8`);\n        await unlink(keyPath).catch(() => {});\n      }\n      resolve({ success: code === 0, output });\n    });\n  });\n}\n"]}