@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
144 lines (143 loc) • 6.02 kB
JavaScript
/**
* The gate-only listener.
*
* **Why a second port exists at all.** The share gate refuses requests carrying
* no token — and the operator's own client carries none. Turning the gate on
* therefore breaks local use, which is why it started life as an env flag that
* needed a restart and an informed decision. A loopback allowlist cannot rescue
* that: cloudflared and every reverse proxy connect from `127.0.0.1`, so
* tunnelled traffic is indistinguishable from the operator's own by origin.
*
* The seam that *does* work is the listener. One port keeps today's behaviour
* for the operator's own client; a second port requires a grant on every
* request, and that is the one you expose. Which port a request arrived on is
* decided by the accepting socket, so nothing a client sends can move it from
* one side to the other.
*
* **Why it starts and stops on its own.** A port that requires a grant is
* useless with no grants issued, and issuing the first grant is exactly the
* moment an operator wants somewhere to point a peer. So the listener follows
* the grant file: it comes up when the first active grant appears and goes away
* when the last one is revoked, without a restart on either edge.
*
* @module proxy/shareListener
*/
import { logger } from "../utils/logger.js";
import { listShareGrants } from "./shareGrants.js";
/** How often the grant file is consulted for the first or last active grant. */
const SUPERVISOR_INTERVAL_MS = 15_000;
/** Default offset from the main port. Explicit configuration always wins. */
export const SHARE_PORT_OFFSET = 1;
/**
* The port the share listener should use.
*
* Precedence is the usual one — an explicit flag, then the environment, then a
* derived default. Deriving `port + 1` rather than picking any free port is
* deliberate: a peer's saved URL and a named tunnel both outlive a restart, so
* the address has to be reproducible.
*/
export function resolveSharePort(args) {
if (args.explicit !== undefined && Number.isFinite(args.explicit)) {
return args.explicit;
}
const raw = (args.env ?? process.env).NEUROLINK_PROXY_SHARE_PORT;
const parsed = Number(raw);
if (raw !== undefined && raw !== "" && Number.isInteger(parsed)) {
return parsed;
}
return args.mainPort + SHARE_PORT_OFFSET;
}
/** Is the share listener switched off entirely? */
export function isShareListenerDisabled(env = process.env) {
const raw = (env.NEUROLINK_PROXY_SHARE_LISTENER ?? "").trim().toLowerCase();
return raw === "0" || raw === "off" || raw === "false" || raw === "no";
}
/** Does this node currently lend anything to anyone? */
export async function hasActiveShareGrants() {
try {
const grants = await listShareGrants();
return grants.some((grant) => grant.state === "active");
}
catch {
// An unreadable grant file is an empty grant set everywhere else in this
// subsystem; opening a public port on a parse error would be the one place
// that guessed the other way.
return false;
}
}
/**
* Keep the share listener's existence in step with the grant file.
*
* `start` and `stop` are injected rather than imported so this stays free of the
* HTTP server: the runtime owns the adaptor, and a poll loop that owns nothing
* is the part worth testing.
*/
export function superviseShareListener(args) {
const hasGrants = args.hasGrants ?? hasActiveShareGrants;
let handle;
let inFlight = false;
let stopped = false;
/** Last failure announced, so a permanent one is not re-logged every cycle. */
let lastFailure;
const poll = async () => {
if (inFlight || stopped) {
return;
}
inFlight = true;
try {
const wanted = await hasGrants();
if (wanted && !handle) {
const started = await args.start();
// `stop()` can land while the listen is still resolving. It saw no
// handle to close, so unless this re-check closes the fresh one the
// port stays bound for the life of the process.
if (stopped) {
await started.close().catch(() => {
// Shutdown is already under way; a failed close changes nothing.
});
return;
}
handle = started;
lastFailure = undefined;
logger.always(`[proxy] share listener up on port ${handle.port} — expose this one, not the main port`);
}
else if (!wanted && handle) {
const closing = handle;
handle = undefined;
await closing.close();
logger.always("[proxy] share listener down — no active grants remain");
}
}
catch (error) {
// A port already in use does not clear on its own, and the supervisor
// retries every cycle. Announce each distinct failure once so the log
// stays readable while the condition persists.
const detail = error instanceof Error ? error.message : String(error);
if (detail !== lastFailure) {
lastFailure = detail;
logger.always(`[proxy] share listener could not start: ${detail} — set --share-port to move it`);
}
}
finally {
inFlight = false;
}
};
const timer = setInterval(() => {
void poll();
}, args.intervalMs ?? SUPERVISOR_INTERVAL_MS);
timer.unref?.();
return {
poll,
stop: async () => {
stopped = true;
clearInterval(timer);
const closing = handle;
handle = undefined;
if (closing) {
await closing.close().catch(() => {
// Shutdown is already under way; a failed close changes nothing.
});
}
},
};
}