← back to Dw Activation Debug TK11314
scripts/diagnose-vision-project.js
42 lines
#!/usr/bin/env node
'use strict';
// Existing Google Cloud credentials; metadata and quota reads only. No generation,
// credential writes, billing changes, quota changes, or full keys in output.
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const { execFileSync } = require('node:child_process');
const { redact } = require('../lib/vision-http');
const account = process.argv[2];
if (!account) throw new Error('Usage: diagnose-vision-project.js <existing-gcloud-account>');
const env = fs.readFileSync(path.join(os.homedir(), 'Projects/secrets-manager/.env'), 'utf8');
const aliases = ['GEMINI_API_KEY', 'GEMINI_API_KEY_WALLCO'];
const keys = aliases.map(alias => (env.match(new RegExp(`^${alias}=(.*)$`, 'm')) || [])[1]?.trim().replace(/^['"]|['"]$/g, ''));
async function main() {
const token = execFileSync('gcloud', ['auth', 'print-access-token', `--account=${account}`], { encoding: 'utf8', stdio: ['ignore','pipe','pipe'] }).trim();
async function read(url) {
const response = await fetch(url, { headers: { Authorization: `Bearer ${token}` }, signal: AbortSignal.timeout(30000) });
return { http: response.status, data: await response.json() };
}
for (let i = 0; i < keys.length; i++) {
if (!keys[i]) { console.log(JSON.stringify({ alias: aliases[i], missing: true })); continue; }
const modelResponse = await fetch('https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash', {
headers: { 'x-goog-api-key': keys[i] }, signal: AbortSignal.timeout(30000),
});
const model = await modelResponse.json();
console.log(JSON.stringify({ alias: aliases[i], nonbillable_model_lookup_http: modelResponse.status,
model: model.name || null, error: redact(model.error?.message, keys) }));
const lookup = await read(`https://apikeys.googleapis.com/v2/keys:lookupKey?keyString=${encodeURIComponent(keys[i])}`);
if (lookup.http !== 200) { console.log(JSON.stringify({ alias: aliases[i], http: lookup.http, error: redact(lookup.data.error?.message, keys) })); continue; }
const parent = lookup.data.parent;
const project = parent?.match(/^projects\/(\d+)/)?.[1];
const info = await read(`https://cloudresourcemanager.googleapis.com/v1/projects/${project}`);
const quota = await read(`https://serviceusage.googleapis.com/v1beta1/projects/${project}/services/generativelanguage.googleapis.com/consumerQuotaMetrics?view=FULL`);
const metrics = (quota.data.metrics || []).filter(metric => /generate|content|spend|bill/i.test(JSON.stringify(metric)));
console.log(JSON.stringify({ alias: aliases[i], projectNumber: project, projectId: info.data.projectId,
projectName: info.data.name, metadataHttp: info.http, quotaHttp: quota.http,
quotaError: redact(quota.data.error?.message, keys), metrics }));
}
}
main().catch(error => { console.error(redact(error.message, keys)); process.exitCode = 1; });