Skills › HyperFrames › media-use › gemini-auth.mjs
gemini-auth.mjs
43 lines · skills/media-use/audio/scripts/lib/gemini-auth.mjs at a595755
1import { spawnSync } from "node:child_process";
2import { fileURLToPath } from "node:url";
3import { pythonInvocation } from "./python.mjs";
5export function geminiConfigured() {
6 return Boolean(
7 process.env.GEMINI_API_KEY ||
8 process.env.GOOGLE_API_KEY ||
9 process.env.GOOGLE_APPLICATION_CREDENTIALS ||
10 process.env.GCS_CREDS,
11 );
12}
14export function geminiAuth({ run = spawnSync } = {}) {
15 const key = process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY;
16 if (key) return { headers: { "x-goog-api-key": key }, secret: key };
17 if (!geminiConfigured()) {
18 throw new Error(
19 "Gemini TTS needs GEMINI_API_KEY or GOOGLE_API_KEY, or service-account credentials (GOOGLE_APPLICATION_CREDENTIALS or GCS_CREDS)",
20 );
21 }
22 const { cmd, args } = pythonInvocation([
23 fileURLToPath(new URL("./gemini-auth.py", import.meta.url)),
24 ]);
25 const result = run(cmd, args, { encoding: "utf8", timeout: 60_000, maxBuffer: 1024 * 1024 });
26 let data;
27 try {
28 data = JSON.parse(result.stdout);
29 } catch {
30 throw new Error(
31 "Gemini service-account authentication failed; check Python and install google-auth requests",
32 );
33 }
34 if (result.status !== 0 || !data.token) {
35 // Do not echo subprocess output: it could contain credentials.
36 throw new Error(
37 "Gemini service-account authentication failed; check service-account JSON, permissions, and Python packages google-auth requests",
38 );
39 }
40 const headers = { Authorization: `Bearer ${data.token}` };
41 if (data.project) headers["x-goog-user-project"] = data.project;
42 return { headers, secret: data.token };
43}