Fix empty Bearer on netx__* by waiting for credentials.

Inject credentials before publish, read the live token per HTTP request, and surface netx_token_missing instead of a silent 401.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-09-05 02:11:20 +08:00
parent 02cc68bee3
commit 027f83dd00
7 changed files with 77 additions and 37 deletions

View file

@ -57,12 +57,6 @@ function encodeQuery(params) {
}
function createNetxClient(connection) {
const base = connection.apiUrl.replace(/\/$/, "");
const headers = {
accept: "application/json"
};
if (connection.token.trim().length > 0) {
headers.authorization = `Bearer ${connection.token.trim()}`;
}
const langParams = () => {
const lang = connection.lang.trim().toLowerCase();
if (lang.startsWith("en"))
@ -70,6 +64,14 @@ function createNetxClient(connection) {
return {};
};
async function request(method, path, options = {}) {
const token = connection.getToken().trim();
if (token.length === 0) {
return {
ok: false,
error: "netx_token_missing",
detail: "Set credential NETX_API_TOKEN (Plugins → Netx Ops or scripts/set-netx-token)."
};
}
const merged = { ...langParams(), ...options.params };
const url = `${base}${path}${encodeQuery(merged)}`;
const timeoutMs = options.timeoutMs ?? connection.timeoutMs;
@ -82,9 +84,15 @@ function createNetxClient(connection) {
};
options.signal?.addEventListener("abort", onOuterAbort, { once: true });
try {
const headers = {
accept: "application/json",
authorization: `Bearer ${token}`
};
if (options.body !== undefined)
headers["content-type"] = "application/json";
const init = {
method,
headers: options.body === undefined ? headers : { ...headers, "content-type": "application/json" },
headers,
signal: controller.signal
};
if (options.body !== undefined)
@ -515,9 +523,9 @@ function tool(name, description, parameters, handler, getClient, timeoutMs) {
function registerNetxTools(ctx, connection) {
const client = createNetxClient({
apiUrl: connection.apiUrl,
token: connection.token,
lang: connection.lang,
timeoutMs: Math.min(connection.toolCallTimeoutMs, 45000)
timeoutMs: Math.min(connection.toolCallTimeoutMs, 45000),
getToken: () => getNetxConnection()?.token ?? ""
});
const getClient = () => client;
const t = connection.toolCallTimeoutMs;
@ -662,7 +670,8 @@ function apply(ctx) {
return;
}
unregister = registerNetxTools(ctx, connection);
ctx.logger.info("netxops-tools: registered netx__* for Ops preset → %s", connection.apiUrl);
const tokenConfigured = connection.token.trim().length > 0;
ctx.logger.info("netxops-tools: registered netx__* for Ops preset → %s tokenConfigured=%s", connection.apiUrl, tokenConfigured);
};
remount();
const stopWatch = watchNetxConnection(() => {