UNPKG

@juspay/neurolink

Version:

The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002

105 lines (104 loc) • 3.83 kB
/** * Proxy auto-update version checker. * * Queries the npm registry for the latest published version of * `@juspay/neurolink` and compares it against the currently running version. * Designed to be non-blocking and failure-tolerant — any error (network, * timeout, parse) returns an explicit failed check without inventing a release. */ import { execFile as execFileCb } from "node:child_process"; import { promisify } from "node:util"; import { logger } from "../utils/logger.js"; const execFile = promisify(execFileCb); /** Timeout (ms) for the `npm view` child process. */ const NPM_VIEW_TIMEOUT_MS = 10_000; /** * Parse a version string of the form `major.minor.patch` into numeric * components. Returns `null` when the string does not match. */ function parseSemVer(version) { const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version.trim()); if (!match) { return null; } return { major: Number(match[1]), minor: Number(match[2]), patch: Number(match[3]), }; } /** * Returns `true` when `latest` is strictly greater than `current`. * * Both arguments must be valid semver strings; returns `false` on any * parse failure so the caller never sees a spurious "update available". */ function isNewerVersion(current, latest) { const cur = parseSemVer(current); const lat = parseSemVer(latest); if (!cur || !lat) { return false; } if (lat.major !== cur.major) { return lat.major > cur.major; } if (lat.minor !== cur.minor) { return lat.minor > cur.minor; } return lat.patch > cur.patch; } // --------------------------------------------------------------------------- // Core check // --------------------------------------------------------------------------- /** * Query npm for the latest version of `@juspay/neurolink` and compare it * against {@link currentVersion}. * * Failure retains the legacy version fallback but marks it unverified. Callers * must not persist it as a successful registry observation. */ export async function checkForUpdate(currentVersion) { const fail = (checkError) => ({ currentVersion, latestVersion: currentVersion, updateAvailable: false, checkSucceeded: false, checkError, }); try { logger.debug("[UpdateChecker] Checking for updates", { currentVersion }); const { stdout } = await execFile("npm", ["view", "@juspay/neurolink", "version", "--json"], { timeout: NPM_VIEW_TIMEOUT_MS }); // `npm view ... --json` wraps the value in double-quotes, e.g. `"9.32.0"` const parsed = JSON.parse(stdout); if (typeof parsed !== "string") { logger.warn("[UpdateChecker] Unexpected npm output type", { type: typeof parsed, }); return fail("Registry returned a non-string version"); } const latestVersion = parsed.trim(); if (!parseSemVer(latestVersion)) { logger.warn("[UpdateChecker] Failed to parse latest version", { latestVersion, }); return fail("Registry returned an invalid version"); } const updateAvailable = isNewerVersion(currentVersion, latestVersion); logger.debug("[UpdateChecker] Version check complete", { currentVersion, latestVersion, updateAvailable, }); return { currentVersion, latestVersion, updateAvailable, checkSucceeded: true, }; } catch (error) { const message = error instanceof Error ? error.message : String(error); logger.warn("[UpdateChecker] Update check failed", { error: message }); return fail("Registry version check failed; see updater diagnostics"); } }