| 61 | * BigQuery so a fix in one place applies to both. |
| 62 | */ |
| 63 | export function parseServiceAccount(json: string): ParsedServiceAccount { |
| 64 | let parsed: unknown |
| 65 | try { |
| 66 | parsed = JSON.parse(json) |
| 67 | } catch (error) { |
| 68 | throw new Error(`serviceAccountJson is not valid JSON: ${toError(error).message}`) |
| 69 | } |
| 70 | if (typeof parsed !== 'object' || parsed === null) { |
| 71 | throw new Error('serviceAccountJson must be a JSON object') |
| 72 | } |
| 73 | const obj = parsed as Record<string, unknown> |
| 74 | const clientEmail = obj.client_email |
| 75 | const privateKey = obj.private_key |
| 76 | if (typeof clientEmail !== 'string' || clientEmail.length === 0) { |
| 77 | throw new Error('serviceAccountJson is missing client_email') |
| 78 | } |
| 79 | if (typeof privateKey !== 'string' || privateKey.length === 0) { |
| 80 | throw new Error('serviceAccountJson is missing private_key') |
| 81 | } |
| 82 | return { clientEmail, privateKey } |
| 83 | } |
| 84 | |
| 85 | /** |
| 86 | * Zod `superRefine` helper that validates a service-account JSON key string |