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

95 lines (94 loc) • 3.94 kB
/** * Dynamically import an optional dependency, converting a missing package into * an actionable error. * * NeuroLink declares 42 `optionalDependencies`, and each loader had grown its * own copy of the same try/catch: check `err.code`, substring-match the package * name, rethrow a friendlier Error. The copies had drifted — some said * `pnpm add`, one said `npm install`, and the phrasing varied per call site. * * Only missing-module failures are intercepted. A package that is installed but * throws while evaluating (syntax error, ESM/CJS interop, a broken transitive * dep) rethrows unchanged — turning those into "please install X" would send * the caller after a package they already have. The same applies to specifiers * that are not installable packages at all (relative paths, file/data URLs): * they rethrow untouched rather than producing an unrunnable install command. * * @param pkg - Module specifier. The install hint is only produced for bare * package names; anything else rethrows the loader's own error. * @param feature - Human-readable capability name, used to open the message. * @returns The imported module namespace, typed as `T` (`unknown` if the * caller does not supply a type argument, since the shape cannot be known * for a dynamic specifier). * @throws The loader's original error, or an `Error` naming the package and * the `pnpm add` command when a bare package is genuinely absent. The * original failure is always preserved on `cause`. * * @example * ```ts * const ExcelJS = await tryImport<typeof import("exceljs")>( * "exceljs", * "Excel file processing", * ); * ``` */ export async function tryImport(pkg, feature) { try { return (await import(/* @vite-ignore */ pkg)); } catch (err) { if (isMissingModule(err, pkg)) { throw new Error(`${feature} requires the "${pkg}" package. Install it with:\n pnpm add ${pkg}`, { cause: err }); } throw err; } } /** * True only when `err` is the module loader failing to resolve `pkg` itself. * * The package name is matched inside quotes because that is how both loaders * format it — ESM `Cannot find package 'x' imported from …`, CJS * `Cannot find module 'x'`. Matching the bare substring instead (as the * hand-rolled copies did) also matches a *transitive* dependency whose path * happens to contain the name, which would blame the wrong package. * * The specifier must also be a bare package name. Without that check a missing * relative path or file URL is rewritten into `pnpm add ./fixtures/thing.mjs`, * which is not a command anyone can run — and this helper is already called * with `file:` and `data:` URLs, so that path is reachable rather than * theoretical. */ function isMissingModule(err, pkg) { if (!(err instanceof Error)) { return false; } if (!isBarePackageSpecifier(pkg)) { return false; } const code = err.code; if (code !== "ERR_MODULE_NOT_FOUND" && code !== "MODULE_NOT_FOUND") { return false; } return err.message.includes(`'${pkg}'`) || err.message.includes(`"${pkg}"`); } /** * True for specifiers that name an installable package — `exceljs`, * `@scope/pkg`, `pkg/sub/path`. * * False for the two things an install hint cannot help with: filesystem paths * (`./x`, `../x`, `/x`, and Windows `C:\x`, which the scheme test below also * rejects) and any URL (`file:`, `data:`, `http:`), including the `node:` * builtins, which are never installed. */ function isBarePackageSpecifier(specifier) { if (specifier.length === 0) { return false; } if (specifier.startsWith("/") || specifier.startsWith("./") || specifier.startsWith("../")) { return false; } // RFC 3986 scheme: ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) ":" return !/^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(specifier); }