#!/usr/bin/env node import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { createRequire } from "node:module"; import { fileURLToPath, pathToFileURL } from "node:url"; import { DISPLAY_CHROME_PATH, DISPLAY_META_PATH, DISPLAY_RUNTIME_HOME, DISPLAY_PROFILE_DIR, DISPLAY_STATE_PATH, ensureDir, ensureParentDir, ensureRuntimeTree, resolveChromePath, resolveMetaWritePath, resolveProfileDir, resolveRuntimeHome, resolveStateWritePath, } from "./lib/runtime-paths.mjs"; import { parseArgs } from "./lib/cli-shared.mjs"; import { extractClientBin } from "./lib/auth-shared.mjs"; const DEFAULT_URL = "https://salesintelligence-dv.oracle.com/ui/dv/ui/project.jsp?pageid=visualAnalyzer&reportmode=presentation&reportpath=%2F%40Catalog%2Fshared%2FTeam%20Sharing%20Area%2FLAD%2FLAD%20Sales%20Operations%2FLAD%20Production%2FLAD%20Knowledge%20One%20View"; const scriptsDir = path.dirname(fileURLToPath(import.meta.url)); const skillHome = path.resolve(scriptsDir, ".."); const skillsHome = path.resolve(skillHome, ".."); function usage() { return `Refresh Oracle Sales Intelligence auth by opening Chrome. This is an optional development and troubleshooting helper. Daily use should prefer scripts/refresh-auth-direct.mjs. Usage: node scripts/refresh-auth-state.mjs [options] Options: --runtime-home Override workspace runtime root (default: ${DISPLAY_RUNTIME_HOME}) --state-path Override auth-state.json output path (default: ${DISPLAY_STATE_PATH}) --meta-path Override session-meta.json output path (default: ${DISPLAY_META_PATH}) --profile-dir Override Chrome profile directory (default: ${DISPLAY_PROFILE_DIR}) --chrome-path Override Chrome executable path (default: ${DISPLAY_CHROME_PATH}) --url Target Oracle DV workbook URL --timeout-ms Wait time for authenticated Oracle DV page (default: 600000) --help Show this help `; } async function pathExists(targetPath) { try { await fs.access(targetPath); return true; } catch { return false; } } function uniquePaths(values) { const seen = new Set(); const result = []; for (const value of values.filter(Boolean)) { const resolved = path.resolve(value); if (seen.has(resolved)) continue; seen.add(resolved); result.push(resolved); } return result; } function bundledRuntimePackageCandidates(packageName) { const execDir = path.dirname(process.execPath || ""); const envNodeModules = [ process.env.CODEX_NODE_MODULES, process.env.CODEX_BUNDLED_NODE_MODULES, process.env.NODE_PATH, ].filter(Boolean); const packageJsonCandidates = []; for (const nodeModulesPath of envNodeModules) { for (const basePath of String(nodeModulesPath).split(path.delimiter)) { if (!basePath) continue; packageJsonCandidates.push(path.join(basePath, packageName, "package.json")); } } if (process.env.CODEX_PRIMARY_RUNTIME_HOME) { packageJsonCandidates.push( path.join( process.env.CODEX_PRIMARY_RUNTIME_HOME, "dependencies", "node", "node_modules", packageName, "package.json", ), ); } packageJsonCandidates.push( path.join(execDir, "node_modules", packageName, "package.json"), path.join(execDir, "..", "node_modules", packageName, "package.json"), path.join(execDir, "..", "..", "node_modules", packageName, "package.json"), path.join( os.homedir(), ".cache", "codex-runtimes", "codex-primary-runtime", "dependencies", "node", "node_modules", packageName, "package.json", ), ); return uniquePaths(packageJsonCandidates); } async function loadPlaywright() { const packageNames = ["playwright", "playwright-core"]; for (const packageName of packageNames) { try { return { runtime: await import(packageName), sourceLabel: `local-module:${packageName}`, }; } catch {} } const sharedSkillPackageJson = path.join(skillsHome, "playwright", "package.json"); if (await pathExists(sharedSkillPackageJson)) { const requireFromSharedSkill = createRequire(sharedSkillPackageJson); for (const packageName of packageNames) { try { return { runtime: requireFromSharedSkill(packageName), sourceLabel: `shared-skill:${packageName}`, }; } catch {} } } for (const packageName of packageNames) { for (const packageJsonPath of bundledRuntimePackageCandidates(packageName)) { if (!(await pathExists(packageJsonPath))) continue; try { const requireFromBundledRuntime = createRequire(packageJsonPath); return { runtime: requireFromBundledRuntime(packageName), sourceLabel: `bundled-runtime:${packageJsonPath}`, }; } catch {} } } throw new Error( [ "Could not load Playwright for the browser auth helper.", "Tried local module resolution, ~/.codex/skills/playwright, and bundled Codex runtime locations.", "Install a shared Playwright runtime under ~/.codex/skills/playwright or run this helper from a Codex environment with bundled node_modules.", ].join(" "), ); } async function ensureChromeExecutable(chromePath) { try { await fs.access(chromePath); } catch { throw new Error( `Could not find a Chrome executable at ${chromePath}. Pass --chrome-path or set ORACLE_SI_CHROME_PATH to a valid Chrome installation.` ); } } export async function main(argv = process.argv.slice(2)) { const args = parseArgs(argv); if (args.help === "true") { console.log(usage()); return; } const runtimeHome = resolveRuntimeHome(args["runtime-home"]); await ensureRuntimeTree(runtimeHome); const statePath = resolveStateWritePath({ explicitPath: args["state-path"], runtimeHome }); const metaPath = resolveMetaWritePath({ explicitPath: args["meta-path"], runtimeHome }); const profileDir = resolveProfileDir({ explicitPath: args["profile-dir"], runtimeHome }); const chromePath = resolveChromePath(args["chrome-path"]); const targetUrl = args.url || process.env.ORACLE_SI_TARGET_URL || DEFAULT_URL; const timeoutMs = Number(args["timeout-ms"] || 10 * 60 * 1000); await ensureChromeExecutable(chromePath); const { runtime: playwrightRuntime, sourceLabel } = await loadPlaywright(); const { chromium } = playwrightRuntime; await ensureParentDir(statePath); await ensureParentDir(metaPath); await ensureDir(profileDir); console.log(`Opening Chrome profile at ${profileDir}`); console.log(`Using browser automation runtime: ${sourceLabel}`); console.log("Complete Oracle login in the opened window if prompted."); const context = await chromium.launchPersistentContext(profileDir, { executablePath: chromePath, headless: false, ignoreHTTPSErrors: true, viewport: { width: 1600, height: 900 }, }); let headerMeta = null; const requestListener = (request) => { if (headerMeta) return; if (!request.url().includes("/ui/dv/ui/api/")) return; const headers = request.headers(); const csrfToken = headers["x-csrf-token"] || null; const clientBin = headers["x-bitech-clientbin"] || null; if (!csrfToken || !clientBin) return; headerMeta = { xCsrfToken: csrfToken, xBitechClientbin: clientBin, referer: headers.referer || targetUrl, targetUrl, capturedAt: new Date().toISOString(), }; }; context.on("request", requestListener); try { const page = context.pages()[0] ?? (await context.newPage()); await page.goto(targetUrl, { waitUntil: "domcontentloaded", timeout: 120000 }); const deadline = Date.now() + timeoutMs; while (Date.now() < deadline) { await page.waitForTimeout(2000); const url = page.url(); const title = await page.title().catch(() => ""); console.log(`Waiting for Oracle Analytics session: ${url}`); const authenticated = url.startsWith("https://salesintelligence-dv.oracle.com/") && !url.includes("signon.oracle.com") && !url.includes("signon-int.oracle.com") && /Oracle Analytics|LAD Knowledge One View/i.test(title || url); if (!authenticated) continue; const html = await page.content(); const fallbackClientBin = extractClientBin(html); if (!headerMeta) { await page.reload({ waitUntil: "domcontentloaded" }).catch(() => {}); await page.waitForTimeout(4000); } if (!headerMeta?.xBitechClientbin && fallbackClientBin) { headerMeta = { ...(headerMeta || {}), xCsrfToken: headerMeta?.xCsrfToken || null, xBitechClientbin: fallbackClientBin, referer: headerMeta?.referer || targetUrl, targetUrl, capturedAt: new Date().toISOString(), }; } if (!headerMeta?.xCsrfToken || !headerMeta?.xBitechClientbin) { continue; } const state = await context.storageState(); await fs.writeFile(statePath, `${JSON.stringify(state, null, 2)}\n`, "utf8"); await fs.writeFile(metaPath, `${JSON.stringify(headerMeta, null, 2)}\n`, "utf8"); console.log(`Saved auth state to ${statePath}`); console.log(`Saved session metadata to ${metaPath}`); return; } throw new Error(`Timed out waiting for an authenticated Oracle DV page after ${timeoutMs}ms.`); } finally { context.off("request", requestListener); await context.close().catch(() => {}); } } const entryUrl = process.argv[1] ? pathToFileURL(path.resolve(process.argv[1])).href : null; if (import.meta.url === entryUrl) { main().catch((error) => { console.error(error.message); process.exitCode = 1; }); }