import fs from "node:fs"; import path from "node:path"; import { pathToFileURL } from "node:url"; import { writeTextFileIfChanged } from "./runtime-postbuild-shared.mjs"; const GENERATED_BY = "scripts/generate-bundled-provider-auth-env-vars.mjs"; const DEFAULT_OUTPUT_PATH = "src/plugins/bundled-provider-auth-env-vars.generated.ts"; function readIfExists(filePath) { try { return fs.readFileSync(filePath, "utf8"); } catch { return null; } } function normalizeProviderAuthEnvVars(providerAuthEnvVars) { if ( !providerAuthEnvVars || typeof providerAuthEnvVars !== "object" || Array.isArray(providerAuthEnvVars) ) { return []; } return Object.entries(providerAuthEnvVars) .map(([providerId, envVars]) => { const normalizedProviderId = providerId.trim(); const normalizedEnvVars = Array.isArray(envVars) ? envVars.map((value) => String(value).trim()).filter(Boolean) : []; if (!normalizedProviderId || normalizedEnvVars.length === 0) { return null; } return [normalizedProviderId, normalizedEnvVars]; }) .filter(Boolean) .toSorted(([left], [right]) => left.localeCompare(right)); } export function collectBundledProviderAuthEnvVars(params = {}) { const repoRoot = path.resolve(params.repoRoot ?? process.cwd()); const extensionsRoot = path.join(repoRoot, "extensions"); if (!fs.existsSync(extensionsRoot)) { return {}; } const entries = new Map(); for (const dirent of fs.readdirSync(extensionsRoot, { withFileTypes: true })) { if (!dirent.isDirectory()) { continue; } const manifestPath = path.join(extensionsRoot, dirent.name, "openclaw.plugin.json"); if (!fs.existsSync(manifestPath)) { continue; } const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8")); for (const [providerId, envVars] of normalizeProviderAuthEnvVars( manifest.providerAuthEnvVars, )) { entries.set(providerId, envVars); } } return Object.fromEntries( [...entries.entries()].toSorted(([left], [right]) => left.localeCompare(right)), ); } export function renderBundledProviderAuthEnvVarModule(entries) { const renderedEntries = Object.entries(entries) .map(([providerId, envVars]) => { const renderedKey = /^[$A-Z_a-z][\w$]*$/u.test(providerId) ? providerId : JSON.stringify(providerId); const renderedEnvVars = envVars.map((value) => JSON.stringify(value)).join(", "); return ` ${renderedKey}: [${renderedEnvVars}],`; }) .join("\n"); return `// Auto-generated by ${GENERATED_BY}. Do not edit directly. export const BUNDLED_PROVIDER_AUTH_ENV_VAR_CANDIDATES = { ${renderedEntries} } as const satisfies Record; `; } export function writeBundledProviderAuthEnvVarModule(params = {}) { const repoRoot = path.resolve(params.repoRoot ?? process.cwd()); const outputPath = path.resolve(repoRoot, params.outputPath ?? DEFAULT_OUTPUT_PATH); const next = renderBundledProviderAuthEnvVarModule( collectBundledProviderAuthEnvVars({ repoRoot }), ); const current = readIfExists(outputPath); const changed = current !== next; if (params.check) { return { changed, wrote: false, outputPath, }; } return { changed, wrote: writeTextFileIfChanged(outputPath, next), outputPath, }; } if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) { const result = writeBundledProviderAuthEnvVarModule({ check: process.argv.includes("--check"), }); if (result.changed) { if (process.argv.includes("--check")) { console.error( `[bundled-provider-auth-env-vars] stale generated output at ${path.relative(process.cwd(), result.outputPath)}`, ); process.exitCode = 1; } else { console.log( `[bundled-provider-auth-env-vars] wrote ${path.relative(process.cwd(), result.outputPath)}`, ); } } }