@nocoo/bat 3.3.0 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bat.js +153 -6
- package/package.json +1 -1
package/dist/bat.js
CHANGED
|
@@ -3093,7 +3093,7 @@ var init_connect = () => {};
|
|
|
3093
3093
|
var init_settings = () => {};
|
|
3094
3094
|
|
|
3095
3095
|
// ../shared/dist/version.js
|
|
3096
|
-
var BAT_VERSION = "3.
|
|
3096
|
+
var BAT_VERSION = "3.4.0";
|
|
3097
3097
|
|
|
3098
3098
|
// ../shared/dist/workstations.js
|
|
3099
3099
|
function fail(error) {
|
|
@@ -3726,7 +3726,7 @@ function validateWorkstationPairStart(input) {
|
|
|
3726
3726
|
}
|
|
3727
3727
|
};
|
|
3728
3728
|
}
|
|
3729
|
-
var WORKSTATION_INTERVAL_SECONDS = 600, WORKSTATION_PING_COUNT = 3, WORKSTATION_MAX_TARGETS = 100, WORKSTATION_BODY_MAX_BYTES = 65536, WORKSTATION_REPORT_SKEW_SECONDS = 300, WORKSTATION_MAX_RUN_MS = 120000, WORKSTATION_STALE_AFTER_SECONDS, WORKSTATION_NAME_MAX_LENGTH = 64, WORKSTATION_PAIRING_TTL_SECONDS = 300, WORKSTATION_PAIRING_ALPHABET = "ABCDEFGHJKMNPQRSTVWXYZ23456789", WORKSTATION_PAIRING_LENGTH = 8, WORKSTATION_LIMITS, WORKSTATION_CONNECTIVITY_STATUSES, UUID_PATTERN, IPV4_PATTERN, PKCE_CHALLENGE_PATTERN, PKCE_VERIFIER_PATTERN, WORKSTATION_TOKEN_PATTERN, IPV6_CHARS, REPORT_KEYS, CPU_KEYS, MEM_KEYS, DISK_KEYS, NETWORK_KEYS, INTERFACE_KEYS, ADDRESS_KEYS, CONNECTIVITY_KEYS, TARGET_KEYS, TARGETS_RESPONSE_KEYS, LOGIN_EXCHANGE_KEYS, PAIR_START_KEYS;
|
|
3729
|
+
var WORKSTATION_INTERVAL_SECONDS = 600, WORKSTATION_PING_COUNT = 3, WORKSTATION_MAX_TARGETS = 100, WORKSTATION_BODY_MAX_BYTES = 65536, WORKSTATION_REPORT_SKEW_SECONDS = 300, WORKSTATION_MAX_RUN_MS = 120000, WORKSTATION_STALE_AFTER_SECONDS, WORKSTATION_NAME_MAX_LENGTH = 64, WORKSTATION_PAIRING_TTL_SECONDS = 300, WORKSTATION_PAIRING_ALPHABET = "ABCDEFGHJKMNPQRSTVWXYZ23456789", WORKSTATION_PAIRING_LENGTH = 8, WORKSTATION_LIMITS, WORKSTATION_CONNECTIVITY_STATUSES, WORKSTATION_REPORTS_MAX_LIMIT = 20, WORKSTATION_REPORTS_DEFAULT_LIMIT = 3, UUID_PATTERN, IPV4_PATTERN, PKCE_CHALLENGE_PATTERN, PKCE_VERIFIER_PATTERN, WORKSTATION_TOKEN_PATTERN, IPV6_CHARS, REPORT_KEYS, CPU_KEYS, MEM_KEYS, DISK_KEYS, NETWORK_KEYS, INTERFACE_KEYS, ADDRESS_KEYS, CONNECTIVITY_KEYS, TARGET_KEYS, TARGETS_RESPONSE_KEYS, LOGIN_EXCHANGE_KEYS, PAIR_START_KEYS;
|
|
3730
3730
|
var init_workstations = __esm(() => {
|
|
3731
3731
|
WORKSTATION_STALE_AFTER_SECONDS = WORKSTATION_INTERVAL_SECONDS * 3;
|
|
3732
3732
|
WORKSTATION_LIMITS = {
|
|
@@ -4544,7 +4544,7 @@ async function exchangeLogin(origins, input, options = {}) {
|
|
|
4544
4544
|
if (!validated.ok) {
|
|
4545
4545
|
throw new Error(`invalid exchange request: ${validated.error}`);
|
|
4546
4546
|
}
|
|
4547
|
-
const client = new HttpClient(origins.machine, undefined, options.timeoutMs ?? REQUEST_TIMEOUT_MS, options.signal);
|
|
4547
|
+
const client = new HttpClient(origins.machine, undefined, options.timeoutMs ?? REQUEST_TIMEOUT_MS, options.signal, options.fetchImpl);
|
|
4548
4548
|
const raw = await client.post("/api/workstation-auth/exchange", validated.value);
|
|
4549
4549
|
return parseExchangeOutput(raw, origins.machine);
|
|
4550
4550
|
}
|
|
@@ -4627,7 +4627,7 @@ async function startPairing(origins, input, options = {}) {
|
|
|
4627
4627
|
if (!validated.ok) {
|
|
4628
4628
|
throw new Error(`invalid pairing request: ${validated.error}`);
|
|
4629
4629
|
}
|
|
4630
|
-
const client = new HttpClient(origins.machine, undefined, options.timeoutMs ?? REQUEST_TIMEOUT_MS, options.signal);
|
|
4630
|
+
const client = new HttpClient(origins.machine, undefined, options.timeoutMs ?? REQUEST_TIMEOUT_MS, options.signal, options.fetchImpl);
|
|
4631
4631
|
const raw = await client.post("/api/workstation-auth/pair", validated.value);
|
|
4632
4632
|
if (typeof raw !== "object" || raw === null) {
|
|
4633
4633
|
throw new Error("pairing start returned no object");
|
|
@@ -4654,7 +4654,7 @@ async function pairingStatus(origins, pairingCode, options = {}) {
|
|
|
4654
4654
|
if (normalized === null) {
|
|
4655
4655
|
throw new Error("invalid pairing code");
|
|
4656
4656
|
}
|
|
4657
|
-
const client = new HttpClient(origins.machine, undefined, options.timeoutMs ?? REQUEST_TIMEOUT_MS, options.signal);
|
|
4657
|
+
const client = new HttpClient(origins.machine, undefined, options.timeoutMs ?? REQUEST_TIMEOUT_MS, options.signal, options.fetchImpl);
|
|
4658
4658
|
const raw = await client.get(`/api/workstation-auth/pair/${normalized}`);
|
|
4659
4659
|
if (typeof raw !== "object" || raw === null) {
|
|
4660
4660
|
throw new Error("pairing status returned no object");
|
|
@@ -4670,6 +4670,14 @@ async function pairingStatus(origins, pairingCode, options = {}) {
|
|
|
4670
4670
|
expires_at: typeof record.expires_at === "number" ? record.expires_at : 0
|
|
4671
4671
|
};
|
|
4672
4672
|
}
|
|
4673
|
+
async function fetchReports(workerUrl, token, limit, options = {}) {
|
|
4674
|
+
const client = new HttpClient(workerUrl, token, options.timeoutMs ?? REQUEST_TIMEOUT_MS, options.signal, options.fetchImpl);
|
|
4675
|
+
const raw = await client.get(`/api/workstation-probe/reports?limit=${encodeURIComponent(String(limit))}`);
|
|
4676
|
+
if (typeof raw !== "object" || raw === null || !Array.isArray(raw.data)) {
|
|
4677
|
+
throw new Error("report readback returned no data array");
|
|
4678
|
+
}
|
|
4679
|
+
return raw;
|
|
4680
|
+
}
|
|
4673
4681
|
var REQUEST_TIMEOUT_MS = 30000, UPLOAD_ATTEMPTS = 3, RETRY_BASE_MS = 500;
|
|
4674
4682
|
var init_api2 = __esm(() => {
|
|
4675
4683
|
init_dist4();
|
|
@@ -5137,6 +5145,143 @@ var init_scheduler = __esm(() => {
|
|
|
5137
5145
|
`);
|
|
5138
5146
|
});
|
|
5139
5147
|
|
|
5148
|
+
// src/workstation/detail.ts
|
|
5149
|
+
function describeLimit(limit) {
|
|
5150
|
+
if (limit === undefined) {
|
|
5151
|
+
return WORKSTATION_REPORTS_DEFAULT_LIMIT;
|
|
5152
|
+
}
|
|
5153
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > WORKSTATION_REPORTS_MAX_LIMIT) {
|
|
5154
|
+
throw new Error(`--limit must be an integer between 1 and ${WORKSTATION_REPORTS_MAX_LIMIT}`);
|
|
5155
|
+
}
|
|
5156
|
+
return limit;
|
|
5157
|
+
}
|
|
5158
|
+
function answering(connectivity) {
|
|
5159
|
+
return connectivity.filter((entry) => entry.status === "reachable" || entry.status === "partial").length;
|
|
5160
|
+
}
|
|
5161
|
+
function averageRtt(entry) {
|
|
5162
|
+
const values = entry.rtts_ms.filter((value) => value !== null);
|
|
5163
|
+
if (values.length === 0) {
|
|
5164
|
+
return "—";
|
|
5165
|
+
}
|
|
5166
|
+
const mean = values.reduce((total, value) => total + value, 0) / values.length;
|
|
5167
|
+
return `${Math.round(mean * 10) / 10} ms`;
|
|
5168
|
+
}
|
|
5169
|
+
function loss(entry) {
|
|
5170
|
+
if (entry.status === "error" || entry.status === "unsupported") {
|
|
5171
|
+
return "—";
|
|
5172
|
+
}
|
|
5173
|
+
if (entry.sent <= 0) {
|
|
5174
|
+
return "—";
|
|
5175
|
+
}
|
|
5176
|
+
return `${Math.round((entry.sent - entry.received) / entry.sent * 1000) / 10}%`;
|
|
5177
|
+
}
|
|
5178
|
+
function clock(seconds) {
|
|
5179
|
+
return new Date(seconds * 1000).toLocaleString();
|
|
5180
|
+
}
|
|
5181
|
+
async function runWorkstationDetail(deps) {
|
|
5182
|
+
const credential = deps.credential ?? readCredential(deps.paths);
|
|
5183
|
+
if (!credential) {
|
|
5184
|
+
error("Not logged in — run 'bat workstation login' first.");
|
|
5185
|
+
return 1;
|
|
5186
|
+
}
|
|
5187
|
+
let limit;
|
|
5188
|
+
try {
|
|
5189
|
+
limit = describeLimit(deps.limit);
|
|
5190
|
+
} catch (err) {
|
|
5191
|
+
error(err.message);
|
|
5192
|
+
return 1;
|
|
5193
|
+
}
|
|
5194
|
+
let response;
|
|
5195
|
+
try {
|
|
5196
|
+
response = await (deps.fetch ?? fetchReports)(credential.worker_url, credential.token, limit);
|
|
5197
|
+
} catch (err) {
|
|
5198
|
+
const message = err.message;
|
|
5199
|
+
error(`Could not read reports: ${message}`);
|
|
5200
|
+
if (/Route not allowed|404|not support/i.test(message)) {
|
|
5201
|
+
info("This deployment does not expose report readback yet; upgrade the server first.");
|
|
5202
|
+
}
|
|
5203
|
+
return 1;
|
|
5204
|
+
}
|
|
5205
|
+
if (deps.json === true) {
|
|
5206
|
+
console.log(JSON.stringify({
|
|
5207
|
+
workstation_id: credential.workstation_id,
|
|
5208
|
+
worker_url: credential.worker_url,
|
|
5209
|
+
limit: response.limit,
|
|
5210
|
+
reports: response.data
|
|
5211
|
+
}, null, 2));
|
|
5212
|
+
return 0;
|
|
5213
|
+
}
|
|
5214
|
+
info(`Workstation ${credential.workstation_id} · ${credential.worker_url}`);
|
|
5215
|
+
const latest = response.data[0];
|
|
5216
|
+
if (!latest) {
|
|
5217
|
+
error("No reports stored yet — run 'bat workstation probe' once.");
|
|
5218
|
+
return 1;
|
|
5219
|
+
}
|
|
5220
|
+
success(`Newest report ${clock(latest.finished_at)} · CPU ${latest.cpu_usage_pct ?? "—"}% · memory ${latest.mem_used_pct}% · ${answering(latest.connectivity)}/${latest.connectivity.length} answering`);
|
|
5221
|
+
table(["Target", "Address", "ICMP", "Average", "Loss", "RTTs"], latest.connectivity.map((entry) => [
|
|
5222
|
+
entry.server_id,
|
|
5223
|
+
`${entry.address} v${entry.family}`,
|
|
5224
|
+
entry.status,
|
|
5225
|
+
averageRtt(entry),
|
|
5226
|
+
loss(entry),
|
|
5227
|
+
entry.rtts_ms.map((value) => value === null ? "—" : `${Math.round(value * 10) / 10}`).join(" / ")
|
|
5228
|
+
]));
|
|
5229
|
+
if (response.data.length > 1) {
|
|
5230
|
+
info("");
|
|
5231
|
+
info(`Earlier reports (${response.data.length - 1})`);
|
|
5232
|
+
table(["Finished", "CPU", "Memory", "Answering"], response.data.slice(1).map((entry) => [
|
|
5233
|
+
clock(entry.finished_at),
|
|
5234
|
+
entry.cpu_usage_pct === null ? "—" : `${entry.cpu_usage_pct}%`,
|
|
5235
|
+
`${entry.mem_used_pct}%`,
|
|
5236
|
+
`${answering(entry.connectivity)}/${entry.connectivity.length}`
|
|
5237
|
+
]));
|
|
5238
|
+
}
|
|
5239
|
+
return 0;
|
|
5240
|
+
}
|
|
5241
|
+
var init_detail = __esm(() => {
|
|
5242
|
+
init_dist4();
|
|
5243
|
+
init_output();
|
|
5244
|
+
init_api2();
|
|
5245
|
+
init_store();
|
|
5246
|
+
});
|
|
5247
|
+
|
|
5248
|
+
// src/commands/workstation/detail.ts
|
|
5249
|
+
async function runDetailCommand(deps = {}) {
|
|
5250
|
+
return await runWorkstationDetail({
|
|
5251
|
+
paths: deps.paths ?? getWorkstationPaths(),
|
|
5252
|
+
...deps.limit !== undefined ? { limit: deps.limit } : {},
|
|
5253
|
+
...deps.json ? { json: true } : {}
|
|
5254
|
+
});
|
|
5255
|
+
}
|
|
5256
|
+
var detail_default;
|
|
5257
|
+
var init_detail2 = __esm(() => {
|
|
5258
|
+
init_dist3();
|
|
5259
|
+
init_detail();
|
|
5260
|
+
init_store();
|
|
5261
|
+
detail_default = defineCommand({
|
|
5262
|
+
meta: {
|
|
5263
|
+
name: "detail",
|
|
5264
|
+
description: "Show the newest reports and per-target probe results"
|
|
5265
|
+
},
|
|
5266
|
+
args: {
|
|
5267
|
+
limit: {
|
|
5268
|
+
type: "string",
|
|
5269
|
+
description: "How many recent reports to read (1-20, default 3)"
|
|
5270
|
+
},
|
|
5271
|
+
json: {
|
|
5272
|
+
type: "boolean",
|
|
5273
|
+
description: "Print the raw report payload"
|
|
5274
|
+
}
|
|
5275
|
+
},
|
|
5276
|
+
async run({ args }) {
|
|
5277
|
+
process.exitCode = await runDetailCommand({
|
|
5278
|
+
...typeof args.limit === "string" && args.limit !== "" ? { limit: Number(args.limit) } : {},
|
|
5279
|
+
...args.json ? { json: true } : {}
|
|
5280
|
+
});
|
|
5281
|
+
}
|
|
5282
|
+
});
|
|
5283
|
+
});
|
|
5284
|
+
|
|
5140
5285
|
// src/workstation/headless.ts
|
|
5141
5286
|
async function performHeadlessLogin(deps) {
|
|
5142
5287
|
const now = deps.now ?? (() => Math.floor(Date.now() / 1000));
|
|
@@ -7957,6 +8102,7 @@ var init_status = __esm(() => {
|
|
|
7957
8102
|
var workstation_default;
|
|
7958
8103
|
var init_workstation = __esm(() => {
|
|
7959
8104
|
init_dist3();
|
|
8105
|
+
init_detail2();
|
|
7960
8106
|
init_login3();
|
|
7961
8107
|
init_logout();
|
|
7962
8108
|
init_probe();
|
|
@@ -7969,6 +8115,7 @@ var init_workstation = __esm(() => {
|
|
|
7969
8115
|
},
|
|
7970
8116
|
subCommands: {
|
|
7971
8117
|
login: login_default2,
|
|
8118
|
+
detail: detail_default,
|
|
7972
8119
|
setup: setup_default,
|
|
7973
8120
|
probe: probe_default,
|
|
7974
8121
|
status: status_default3,
|
|
@@ -9496,7 +9643,7 @@ function runChecks(facts) {
|
|
|
9496
9643
|
id: "assets-profile",
|
|
9497
9644
|
label: "Assets profile",
|
|
9498
9645
|
status: "warn",
|
|
9499
|
-
detail: `not configured at ${facts.assetsConfigPath} (
|
|
9646
|
+
detail: `not configured at ${facts.assetsConfigPath} — only agent, asset, binding and heartbeat commands need it (run 'bat login')`
|
|
9500
9647
|
});
|
|
9501
9648
|
} else {
|
|
9502
9649
|
const invalid = validateConfig(facts.assetsConfig);
|