@jeffusion/bungee 6.11.3 → 6.13.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.
Files changed (2) hide show
  1. package/dist/index.js +84 -47
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -11960,7 +11960,7 @@ var require_winston = __commonJS(function(exports) {
11960
11960
 
11961
11961
  // ../../node_modules/object-hash/index.js
11962
11962
  var require_object_hash = __commonJS(function(exports, module) {
11963
- var crypto = __require("crypto");
11963
+ var crypto2 = __require("crypto");
11964
11964
  exports = module.exports = objectHash;
11965
11965
  function objectHash(object, options) {
11966
11966
  options = applyDefaults(object, options);
@@ -11978,7 +11978,7 @@ var require_object_hash = __commonJS(function(exports, module) {
11978
11978
  exports.keysMD5 = function(object) {
11979
11979
  return objectHash(object, { algorithm: "md5", encoding: "hex", excludeValues: true });
11980
11980
  };
11981
- var hashes = crypto.getHashes ? crypto.getHashes().slice() : ["sha1", "md5"];
11981
+ var hashes = crypto2.getHashes ? crypto2.getHashes().slice() : ["sha1", "md5"];
11982
11982
  hashes.push("passthrough");
11983
11983
  var encodings = ["buffer", "hex", "binary", "base64"];
11984
11984
  function applyDefaults(object, sourceOptions) {
@@ -12024,7 +12024,7 @@ var require_object_hash = __commonJS(function(exports, module) {
12024
12024
  function hash(object, options) {
12025
12025
  var hashingStream;
12026
12026
  if (options.algorithm !== "passthrough") {
12027
- hashingStream = crypto.createHash(options.algorithm);
12027
+ hashingStream = crypto2.createHash(options.algorithm);
12028
12028
  } else {
12029
12029
  hashingStream = new PassThrough;
12030
12030
  }
@@ -16112,7 +16112,7 @@ var require_FileStreamRotator = __commonJS(function(exports, module) {
16112
16112
  var fs = __require("fs");
16113
16113
  var path = __require("path");
16114
16114
  var moment = require_moment();
16115
- var crypto = __require("crypto");
16115
+ var crypto2 = __require("crypto");
16116
16116
  var EventEmitter = __require("events");
16117
16117
  var FileStreamRotator = {};
16118
16118
  module.exports = FileStreamRotator;
@@ -16241,7 +16241,7 @@ var require_FileStreamRotator = __commonJS(function(exports, module) {
16241
16241
  }
16242
16242
  };
16243
16243
  function removeFile(file, verbose) {
16244
- if (file.hash === crypto.createHash(file.hashType).update(file.name + "LOG_FILE" + file.date).digest("hex")) {
16244
+ if (file.hash === crypto2.createHash(file.hashType).update(file.name + "LOG_FILE" + file.date).digest("hex")) {
16245
16245
  try {
16246
16246
  if (fs.existsSync(file.name)) {
16247
16247
  fs.unlinkSync(file.name);
@@ -16308,7 +16308,7 @@ var require_FileStreamRotator = __commonJS(function(exports, module) {
16308
16308
  audit.files.push({
16309
16309
  date: time,
16310
16310
  name: logfile,
16311
- hash: crypto.createHash(audit.hashType).update(logfile + "LOG_FILE" + time).digest("hex")
16311
+ hash: crypto2.createHash(audit.hashType).update(logfile + "LOG_FILE" + time).digest("hex")
16312
16312
  });
16313
16313
  if (audit.keep.days) {
16314
16314
  var oldestDate = moment().subtract(audit.keep.amount, "days").valueOf();
@@ -17324,7 +17324,9 @@ function encodeDaemonMetadataV1(value) {
17324
17324
  fail("message_too_large", "daemon metadata exceeds 4 KiB");
17325
17325
  return result;
17326
17326
  }
17327
+
17327
17328
  // ../types/dist/types.js
17329
+ var DEFAULT_BODY_LOG_MAX_BYTES = 64 * 1024;
17328
17330
  var DEFAULT_WEBSOCKET_MAX_MESSAGE_BYTES = 16 * 1024 * 1024;
17329
17331
  // ../types/dist/publication-policy.js
17330
17332
  var DEFAULT_PUBLICATION_POLICY = Object.freeze({
@@ -17800,7 +17802,7 @@ function formatDaemonFileAclError(error) {
17800
17802
  return `acl_operation=${operation} outcome=${outcome}` + ` last_phase=${lastPhase} kill_returned_true=${diagnostic.kill_returned_true === true}` + ` spawn_event=${diagnostic.spawn_event === true} exit_event=${diagnostic.exit_event === true}` + ` close_event=${diagnostic.close_event === true}` + ` target_kind=${targetKind} exit_code=${exitCode}`;
17801
17803
  }
17802
17804
  function boundedElapsed(startedAt, deadlineMs) {
17803
- return Math.min(deadlineMs, Math.max(0, Date.now() - startedAt));
17805
+ return Math.min(deadlineMs, Math.max(0, Math.round(performance.now() - startedAt)));
17804
17806
  }
17805
17807
  function selectWindowsAclExecutable(environment) {
17806
17808
  const programFiles = environment.ProgramFiles;
@@ -17834,7 +17836,7 @@ function processDiagnostic(operation, startedAt, phase, environment, deadlineMs,
17834
17836
  };
17835
17837
  }
17836
17838
  async function runPowerShell(operation, script, environment, deadlineMs) {
17837
- const startedAt = Date.now();
17839
+ const startedAt = performance.now();
17838
17840
  let phase = null;
17839
17841
  let child;
17840
17842
  try {
@@ -21683,12 +21685,10 @@ async function upgradeCommand(options = {}) {
21683
21685
  }
21684
21686
 
21685
21687
  // src/commands/config-io.ts
21686
- var OPERATION_TIMEOUT_MS = 15000;
21687
- var OPERATION_POLL_INTERVAL_MS = 100;
21688
21688
  function endpoint(options, path) {
21689
21689
  const host = options.host ?? "localhost";
21690
21690
  const port = options.port ?? DEFAULT_MANAGEMENT_PORT;
21691
- return `http://${host}:${port}/api/config/${path}`;
21691
+ return `http://${host}:${port}/api/config${path === "" ? "" : `/${path}`}`;
21692
21692
  }
21693
21693
  async function writeFile(path, content) {
21694
21694
  await Bun.write(path, content);
@@ -21698,6 +21698,31 @@ function headers(token) {
21698
21698
  ...token === undefined ? {} : { authorization: `Bearer ${token}` }
21699
21699
  };
21700
21700
  }
21701
+ function acknowledgement(value) {
21702
+ if (typeof value !== "object" || value === null)
21703
+ return null;
21704
+ const { operation_id, revision } = value;
21705
+ if (typeof operation_id !== "string" || operation_id.length === 0 || typeof revision !== "number" || !Number.isSafeInteger(revision) || revision <= 0)
21706
+ return null;
21707
+ return { operation_id, revision };
21708
+ }
21709
+ function currentRevision(value) {
21710
+ if (typeof value !== "object" || value === null)
21711
+ return null;
21712
+ const revision = value.revision;
21713
+ return typeof revision === "number" && Number.isSafeInteger(revision) && revision > 0 ? revision : null;
21714
+ }
21715
+ function unknownOutcome(mutationId, cause) {
21716
+ return new Error(`Import result is unknown; check whether the configuration was saved before retrying. Reference ${mutationId}`, { cause });
21717
+ }
21718
+ function reportedResultUnknown(body) {
21719
+ try {
21720
+ const value = JSON.parse(body);
21721
+ return value.error === "result_unknown";
21722
+ } catch {
21723
+ return false;
21724
+ }
21725
+ }
21701
21726
  async function exportCommand(options) {
21702
21727
  const response = await fetch(endpoint(options, "export"), {
21703
21728
  headers: headers(options.token)
@@ -21711,52 +21736,64 @@ async function exportCommand(options) {
21711
21736
  }
21712
21737
  async function importCommand(options) {
21713
21738
  const snapshot = await Bun.file(options.file).text();
21739
+ let envelope;
21740
+ try {
21741
+ envelope = JSON.parse(snapshot);
21742
+ } catch (cause) {
21743
+ throw new Error(`Import failed: ${options.file} is not valid JSON`, { cause });
21744
+ }
21745
+ const currentResponse = await fetch(endpoint(options, ""), {
21746
+ headers: headers(options.token)
21747
+ });
21748
+ if (!currentResponse.ok) {
21749
+ const body = await currentResponse.text();
21750
+ throw new Error(`Import failed: cannot read current revision: ${currentResponse.status} ${body}`);
21751
+ }
21752
+ let current;
21753
+ try {
21754
+ current = await currentResponse.json();
21755
+ } catch (cause) {
21756
+ throw new Error("Import failed: current revision response is invalid", { cause });
21757
+ }
21758
+ const expectedRevision = currentRevision(current);
21759
+ if (expectedRevision === null) {
21760
+ throw new Error("Import failed: current revision response is invalid");
21761
+ }
21762
+ const mutationId = crypto.randomUUID();
21714
21763
  const response = await fetch(endpoint(options, "import"), {
21715
21764
  method: "POST",
21716
21765
  headers: { ...headers(options.token), "content-type": "application/json" },
21717
- body: snapshot
21766
+ body: JSON.stringify({ expected_revision: expectedRevision, mutation_id: mutationId, envelope })
21767
+ }).catch((cause) => {
21768
+ throw unknownOutcome(mutationId, cause);
21718
21769
  });
21719
21770
  if (!response.ok) {
21720
- const body = await response.text();
21771
+ let body;
21772
+ try {
21773
+ body = await response.text();
21774
+ } catch (cause) {
21775
+ throw unknownOutcome(mutationId, cause);
21776
+ }
21777
+ if (reportedResultUnknown(body))
21778
+ throw unknownOutcome(mutationId);
21721
21779
  throw new Error(`Import failed: ${response.status} ${body}`);
21722
21780
  }
21723
- const accepted = await response.json();
21724
- const deadline = Date.now() + OPERATION_TIMEOUT_MS;
21725
- let state = accepted;
21726
- while (true) {
21727
- switch (state.operation.state) {
21728
- case "converged":
21729
- console.log(`Config imported from ${options.file}: revision ${accepted.revision} operation ${accepted.operation_id}`);
21730
- return;
21731
- case "degraded":
21732
- throw new Error(`Import failed: operation ${accepted.operation_id} degraded: ${state.operation.error_detail}`);
21733
- case "committed":
21734
- case "publishing":
21735
- case "draining":
21736
- break;
21737
- }
21738
- const remainingMs = deadline - Date.now();
21739
- if (remainingMs <= 0) {
21740
- throw new Error(`Import failed: operation ${accepted.operation_id} timed out after ${OPERATION_TIMEOUT_MS}ms`);
21741
- }
21742
- const poll = await fetch(endpoint(options, `operations/${accepted.operation_id}`), {
21743
- headers: headers(options.token),
21744
- signal: AbortSignal.timeout(remainingMs)
21745
- });
21746
- if (!poll.ok) {
21747
- const body = await poll.text();
21748
- throw new Error(`Import failed: operation poll returned ${poll.status} ${body}`);
21749
- }
21750
- state = await poll.json();
21751
- if (state.operation.result_status === null) {
21752
- await Bun.sleep(Math.min(OPERATION_POLL_INTERVAL_MS, Math.max(0, deadline - Date.now())));
21753
- }
21781
+ let value;
21782
+ try {
21783
+ value = await response.json();
21784
+ } catch (cause) {
21785
+ throw unknownOutcome(mutationId, cause);
21786
+ }
21787
+ const accepted = acknowledgement(value);
21788
+ if (accepted === null || accepted.operation_id !== mutationId) {
21789
+ throw unknownOutcome(mutationId);
21754
21790
  }
21791
+ console.log(`Config saved from ${options.file}`);
21755
21792
  }
21756
21793
  // package.json
21757
21794
  var package_default = {
21758
21795
  name: "@jeffusion/bungee",
21759
- version: "6.11.3",
21796
+ version: "6.13.0",
21760
21797
  description: "High-performance reverse proxy server CLI",
21761
21798
  type: "module",
21762
21799
  bin: {
@@ -21922,8 +21959,8 @@ Usage counts are replacement totals for the specified attempt, applied to its or
21922
21959
  program.command("status").description("Show daemon status and health").action(statusCommand);
21923
21960
  program.command("logs").description("Show daemon logs").option("-f, --follow", "Follow log output").option("-n, --lines <number>", "Number of lines to show", "50").action(logsCommand);
21924
21961
  program.command("ui").description("Open web dashboard from the Management server").option("-p, --port <port>", "Management server port", DEFAULT_MANAGEMENT_PORT).option("-H, --host <host>", "Management server host", "localhost").action(uiCommand);
21925
- program.command("export").description("Export current configuration from the Management server as a versioned snapshot JSON").requiredOption("-o, --file <path>", "Output file path").option("-p, --port <port>", "Management server port", DEFAULT_MANAGEMENT_PORT).option("-H, --host <host>", "Management server host", "localhost").option("-t, --token <token>", "Management auth token").action(exportCommand);
21926
- program.command("import").description("Restore configuration on the Management server from a versioned snapshot JSON").requiredOption("-f, --file <path>", "Snapshot file path").option("-p, --port <port>", "Management server port", DEFAULT_MANAGEMENT_PORT).option("-H, --host <host>", "Management server host", "localhost").option("-t, --token <token>", "Management auth token").action(importCommand);
21962
+ program.command("export").description("Export the current configuration from the Management server as a JSON file").requiredOption("-o, --file <path>", "Output file path").option("-p, --port <port>", "Management server port", DEFAULT_MANAGEMENT_PORT).option("-H, --host <host>", "Management server host", "localhost").option("-t, --token <token>", "Management auth token").action(exportCommand);
21963
+ program.command("import").description("Save a configuration file on the Management server").requiredOption("-f, --file <path>", "Configuration file path").option("-p, --port <port>", "Management server port", DEFAULT_MANAGEMENT_PORT).option("-H, --host <host>", "Management server host", "localhost").option("-t, --token <token>", "Management auth token").action(importCommand);
21927
21964
  program.command("upgrade").description("Upgrade Bungee binary to the latest version").option("-f, --force", "Force re-download even if already up to date").action(upgradeCommand);
21928
21965
  return program;
21929
21966
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jeffusion/bungee",
3
- "version": "6.11.3",
3
+ "version": "6.13.0",
4
4
  "description": "High-performance reverse proxy server CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,8 +13,8 @@
13
13
  "test": "bun test"
14
14
  },
15
15
  "dependencies": {
16
- "@jeffusion/bungee-core": "^6.11.3",
17
- "@jeffusion/bungee-types": "^6.11.3",
16
+ "@jeffusion/bungee-core": "^6.13.0",
17
+ "@jeffusion/bungee-types": "^6.13.0",
18
18
  "cli-progress": "^3.12.0",
19
19
  "commander": "^14.0.1"
20
20
  },